-- ChipExpandImpl.mesa

-- A package to expand Chipmonk geometries for circuit
-- extraction.

-- last modified by E. McCreight, September 27, 1984 5:30 PM
-- written by E. McCreight, December 11, 1981 11:46 AM

DIRECTORY
CellInstPQ,
ChipDRC,
ChipExpand,
ChipFeature,
ChipNetDefs,
ChipOrient,
ChipWire,
LeftFeaturePQ,
MiscDefs,
ppdddefs,
ppdefs,
RightFeaturePQ;

ChipExpandImpl: PROGRAM
IMPORTS CellInstPQ, ChipDRC, ChipExpand,
ChipFeature, ChipNetDefs, ChipOrient,
MiscDefs, ppdddefs, ppdefs
EXPORTS ChipNetDefs, ChipExpand, ppdefs
SHARES ChipExpand =
BEGIN OPEN ppdddefs, ppdefs,
ChipNetDefs, ChipDRC, ChipExpand;

aux: PUBLIC TYPE = CellProto;

levIsConductor: ARRAY level OF BOOLEAN ← wireOK;
joinTo: PUBLIC LONG POINTER TO netPtr ← NIL;
xstrInst: PUBLIC XstrCallPtr ← NIL;

ExtractorFeature: PUBLIC ExtractorFeatureProc;

MakeInstance: PUBLIC PROCEDURE[item: ItemRef,
slice: ChipWire.SlicePtr,
futureFeatures: LeftFeaturePQ.LeftFeaturePQHandle,
presentFeatures: RightFeaturePQ.RightFeaturePQHandle,
cellQ, deadCellQ: CellInstPQ.CellInstPQHandle] =
BEGIN OPEN ChipOrient;
WITH caller: item.head SELECT FROM
cell =>
BEGIN
firstX1: Coord;
itemCount: CARDINAL ← caller.proto.itemCount;
FOR idx: CellIndex ← item.idx, idx+1
WHILE idx<itemCount DO

ExplodeFeatures: PROCEDURE[p: drProc,
joinByMagic: BOOLEAN ← FALSE,
useText: BOOLEAN ← TRUE,
cutPolyGapRequired: BOOLEAN ← FALSE] =
BEGIN

ExtractorNextFeature: PROCEDURE[
x1, y1, x2, y2: locNum, lev: ExtractLevel] =
BEGIN
IF x1<=x2 AND y1<=y2 THEN
BEGIN
innerR: Rect ← ChipOrient.MapRect[
itemInCell: [x1: x1, y1: y1, x2: x2, y2: y2],
cellInstOrient: callLp.idx,
cellSize: [x: callLp.ob.size[0], y: callLp.ob.size[1]],
cellInstPos: [x: callLp.lx, y: callLp.ly]
];
ob: obPtr ← caller.proto.ob;
r: Rect ← ChipOrient.MapRect[
itemInCell: innerR,
cellInstOrient: caller.orient,
cellSize: [x: ob.size[0], y: ob.size[1]]];
min: CoordPoint ← caller.min;
scale: Coord ← coordScale[caller.proto.locNumScale];
cr: CoordRect ← [
x1: min.x+scale*r.x1,
y1: min.y+scale*r.y1,
x2: min.x+scale*r.x2,
y2: min.y+scale*r.y2];

[] ← ChipFeature.NewFeature[cover: cr, lev: lev,
caller: nextItem, lq: futureFeatures];
END;
END; -- of ExtractorNextFeature

NextFeature: PROCEDURE[x1, y1, x2, y2: locNum,
l: level, p: POINTER TO Rect] =
BEGIN

IF x1<=x2 AND y1<=y2 THEN
BEGIN
AddFeature: PROCEDURE[lev: ExtractLevel,
grow: Coord ← 0, net: netPtr ← NIL] =
BEGIN
f ← ChipFeature.NewFeature[
cover: [x1: cr.x1-grow,
y1: cr.y1-grow,
x2: cr.x2+grow,
y2: cr.y2+grow],
lev: lev, caller: nextItem,
lq: futureFeatures];
IF net#NIL THEN f.net ← RefCanonNet[net];
END;

f: FeaturePtr;
innerR: Rect ← ChipOrient.MapRect[
itemInCell: [x1: x1, y1: y1, x2: x2, y2: y2],
cellInstOrient: callLp.idx,
cellSize: [x: callLp.ob.size[0], y: callLp.ob.size[1]],
cellInstPos: [x: callLp.lx, y: callLp.ly]
];
ob: obPtr ← caller.proto.ob;
r: Rect ← ChipOrient.MapRect[
itemInCell: innerR,
cellInstOrient: caller.orient,
cellSize: [x: ob.size[0], y: ob.size[1]]];
min: CoordPoint ← caller.min;
scale: Coord ← coordScale[caller.proto.locNumScale];
cr: CoordRect ← [
x1: min.x+scale*r.x1,
y1: min.y+scale*r.y1,
x2: min.x+scale*r.x2,
y2: min.y+scale*r.y2];

IF l#unknown THEN
BEGIN
f ← ChipFeature.NewFeature[cover: cr, lev: l,
caller: nextItem, lq: futureFeatures];
f.net ← (SELECT TRUE FROM
NOT levIsConductor[l] => NIL,
net=NIL AND useText AND
FindPropValue[callLp, signalName]#NIL =>
(net ← NewQualifiedNet[f: f]),
joinByMagic =>
(net ← JoinNet[net: net, f: f]),
ENDCASE => NIL);

IF joinTo#NIL THEN
BEGIN
f.net ← joinTo↑ ← (IF f.net=NIL
THEN JoinNet[net: joinTo↑, f: f]
ELSE MergeNets[n1: joinTo↑, n2: f.net]);
joinTo ← NIL;
END;

IF doingDRC AND f.net#NIL AND
(joinByMagic -- a contact -- OR
(SELECT f.lev FROM
metal, metal2 => FALSE,
ENDCASE => levIsConductor[l]))
THEN
GetNormalNetId[@f.net].couldBeLogo ← FALSE;

END;

IF doingDRC THEN
SELECT l FROM
bur =>
BEGIN
AddFeature[lev: nGateForbidden, grow: (3*lambda)/2];
AddFeature[lev: pGateForbidden, grow: (3*lambda)/2];
END;
nwel =>
AddFeature[lev: nPlusForbidden, grow: nWellToNPlus];
pPlus =>
AddFeature[lev: nWellRequired, grow: pWellToPPlus];
nwelCont =>
BEGIN
AddFeature[lev: pGateForbidden, grow: 2*Lambda];
AddFeature[lev: pPlusForbidden];
END;
pwelCont =>
BEGIN
AddFeature[lev: nGateForbidden, grow: 2*Lambda];
AddFeature[lev: nPlusForbidden];
END;
cut => IF cutPolyGapRequired THEN
AddFeature[lev: polyForbidden, grow: cutPolyGap,
net: net];
via => AddFeature[lev: cutForbidden,
grow: viaCutGap, net: net];

ENDCASE => NULL;
END;
END; -- of NextFeature

nullOutline: PROCEDURE[a,b,c,d: INTEGER, col: color,
r: POINTER TO Rect] = {NULL};

nullText: PROCEDURE[a,b,c,d: INTEGER, s: STRING,
r: POINTER TO Rect] = {NULL};

featureProcs: drRecord ← [
r: [x1: FIRST[locNum], x2: LAST[locNum],
y1: FIRST[locNum], y2: LAST[locNum]],
bigr: [x1: FIRST[locNum], x2: LAST[locNum],
y1: FIRST[locNum], y2: LAST[locNum]],
orArea: NextFeature, saveArea: NextFeature,
outl: nullOutline, dtxt: nullText, minSize: 0];

net: CanonNetPtr ← NIL;
ExtractorFeature.p ← ExtractorNextFeature;
joinTo ← NIL;
p[ob: callLp.ob, x: 0, y: 0, pr: @featureProcs];
IF net#NIL THEN net ← DeRefNet[net];
END; -- of ExplodeFeatures

callLp: listPtr ← ProtoSeq[@caller][idx];
nextItem: ItemRef ← [@caller, idx];
r: CoordRect ← ItemInWorld[nextItem];

SELECT TRUE FROM
idx=item.idx => firstX1 ← r.x1;
r.x1=firstX1 => NULL;
ENDCASE =>
BEGIN -- re-insert remainder of caller
CellInstPQ.InsertCellInstPQ[p: cellQ,
item: [x: ItemInWorld[[@caller, idx]].x1,
call: [@caller, idx]]];
EXIT;
END;

IF caller.caller.head#NIL OR callLp.selected THEN -- extract it!
WITH ob: callLp.ob SELECT FROM
cell =>
BEGIN
inst: InstancePtr ← instanceZ.NEW[cell Instance ←
[min: [x: r.x1, y: r.y1],
orient: ComposeOrient[cellOrientInWorld: caller.orient,
itemOrientInCell: callLp.idx],
proto: MakeProto[@ob, caller.proto.locNumScale],
caller: nextItem,
sibling: caller.offspring,
nets: cell[]]];
caller.offspring ← inst;
[] ← ProtoSeq[inst]; -- make sure it’s sorted in the
-- orientation in which it’s called
CellInstPQ.InsertCellInstPQ[p: cellQ,
item: [x: ItemInWorld[[inst, 0]].x1, call: [inst, 0]]];
CellInstPQ.InsertCellInstPQ[p: deadCellQ,
item: [x: ItemInWorld[inst.caller].x2, call: [inst, 0]]];
END;
xstr =>
BEGIN
BEGIN -- put transistor instance in structure tree
xstrInst ← instanceZ.NEW[xstr Instance ←
[min: [x: r.x1, y: r.y1],
orient: ComposeOrient[
cellOrientInWorld: caller.orient,
itemOrientInCell: callLp.idx],
proto: MakeProto[@ob, caller.proto.locNumScale],
caller: nextItem,
sibling: caller.offspring,
nets: xstr[]]];
caller.offspring ← xstrInst;
END;
ExplodeFeatures[SELECT TRUE FROM
ob.pullup => exPu0,
ob.angle => exAXstr0,
ENDCASE => exXstr0];
END;
cont => ExplodeFeatures[
p: (SELECT ob.typ FROM
butt => exBC0,
burr => exBuC0,
ENDCASE => ob.p.drawme[0]),
joinByMagic: TRUE, useText: TRUE,
cutPolyGapRequired: (SELECT ob.typ FROM
mDif => TRUE,
ENDCASE => FALSE)];
bus =>
ExplodeFeatures[p: ob.p.drawme[0]];
wire, rect =>
ExplodeFeatures[p: ob.p.drawme[0], useText: TRUE];
ENDCASE => NULL;
ENDLOOP; -- on idx
END; -- of cell
ENDCASE;
END; -- of MakeInstance


ExitInstance: PUBLIC PROCEDURE[inst: InstancePtr] =
BEGIN
WITH dinst: inst SELECT FROM
cell => CheckClusters[@dinst];
ENDCASE => NULL;
END; -- of ExitCellCall


NewQualifiedNet: PROCEDURE[f: FeaturePtr] RETURNS[CanonNetPtr] =
BEGIN
net: netPtr ← NewNet[2];
id: NormalNetIdPtr = GetNormalNetId[@net];
id.source ← NearestCellInstance[f.caller.head];
id.final ← [lev: f.lev, r: f.cover];
id.name ← qualified[see: f.caller.idx];
RETURN[CanonNet[net]];
END;


JoinNet: PROCEDURE[net: NetPtr, f: FeaturePtr]
RETURNS[cn: CanonNetPtr] =
BEGIN
IF net=NIL THEN
BEGIN
cn ← NewNet[2];
WITH did: cn.id SELECT FROM
normal => did.source ← NearestCellInstance[f.caller.head];
ENDCASE => NULL;
END
ELSE cn ← RefCanonNet[net];
IF cn.id.final.r.x2<f.cover.x2 THEN
cn.id.final ← [lev: f.lev, r: f.cover];
END; -- of JoinNet


NearestCellInstance: PUBLIC PROCEDURE[p: InstancePtr]
RETURNS[CellCallPtr] =
BEGIN
WHILE p#NIL DO
WITH dp: p SELECT FROM
cell => RETURN[@dp];
ENDCASE => p ← dp.caller.head;
ENDLOOP;
RETURN[NIL];
END;


CheckClusters: PUBLIC PROCEDURE[call: CellCallPtr] =
BEGIN
callX2: Coord ←
(IF call.caller.head#NIL THEN ItemInWorld[call.caller].x2
ELSE LAST[Coord]);
FOR cluster: ClusterPtr ← call.clusters, cluster.next
WHILE cluster#NIL DO
CheckCluster[call, callX2, @cluster.first];
ENDLOOP;
END; -- of CheckClusters


CheckCluster: PROCEDURE[call: CellCallPtr, callX2: Coord,
cluster: MustConnectPtr] =
BEGIN
mustConnect, nextMustConnect: MustConnectPtr;

PreviousNet: PROCEDURE[net: netPtr] RETURNS[BOOLEAN] =
BEGIN
FOR mcp: MustConnectPtr ← cluster, mcp.next
WHILE mcp#NIL DO
IF net=mcp.net THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
END;

IF cluster.next=NIL THEN RETURN; -- singleton

-- First, try to locate a still-active net for the
-- cluster head.
FOR mustConnect ← cluster, mustConnect.next WHILE
mustConnect#NIL DO
IF callX2<=
(mustConnect.net ← CanonNet[mustConnect.net]).id.final.r.x2
THEN
BEGIN
copyCluster: MustConnect ← cluster↑;
copyMustConnect: MustConnect ← mustConnect↑;
copyCluster.next ← mustConnect.next;
copyMustConnect.next ← cluster.next;
cluster↑ ← copyMustConnect;
mustConnect↑ ← copyCluster;
EXIT;
END;
ENDLOOP;

nextMustConnect ← cluster.next;
cluster.next ← NIL;
FOR mustConnect ← nextMustConnect, nextMustConnect
WHILE mustConnect#NIL DO
mustConnectNet: CanonNetPtr ← mustConnect.net ←
CanonNet[mustConnect.net];
nextMustConnect ← mustConnect.next;
SELECT TRUE FROM
PreviousNet[mustConnectNet] =>
FreeMustConnect[call, mustConnect];
-- same as some previous constraint
ENDCASE =>
BEGIN
mustConnect.next ← cluster.next;
cluster.next ← mustConnect;
END;
ENDLOOP;
END; -- of CheckCluster


FreeMustConnect: PROCEDURE[call: CellCallPtr,
mustConnect: MustConnectPtr] =
BEGIN
mustConnect.net ← DeRefNet[mustConnect.net];
clusterZ.FREE[@mustConnect];
END; -- of FreeMustConnect

ProtoSeq: PUBLIC PROCEDURE[inst: InstancePtr]
RETURNS[ListPtrSeqPtr] =
BEGIN
sortClass: SortClass ← orientToSortClass[inst.orient];
proto: ProtoPtr ← inst.proto;
IF proto.seq[sortClass]=NIL THEN
BEGIN
i: CellIndex ← 0;
lps: ListPtrSeqPtr ← uz.NEW[ListPtrSeq[proto.itemCount]];
FOR lpp: listPtr ← proto.lp, lpp.nxt WHILE lpp#NIL DO
lps[i] ← lpp;
i ← i+1;
ENDLOOP;
SortListPtrSeq[lps, SortOrder[sortClass]];
proto.seq[sortClass] ← lps;
END;
RETURN[proto.seq[sortClass]];
END;

MakeProto: PUBLIC PROCEDURE[ob: obPtr,
locNumScale: LocNumScale ← lambdaRelative, name: STRING ← NIL]
RETURNS[c: ProtoPtr] =
BEGIN
IF ob.auxPnt=NIL THEN
BEGIN -- We’ll have to make one up.
scale: Coord ← coordScale[locNumScale];
cp: ProtoPtr ← ob.auxPnt ← uz.NEW[CellProto ←
[ob: ob,
locNumScale: locNumScale,
stretchMasks: locNumScale=lambdaRelative,
size: [x: scale*ob.size[0],
y: scale*ob.size[1]]]];
count: CARDINAL ← 0;
WITH o: ob SELECT FROM
cell =>
BEGIN
FOR lp: listPtr ← o.ptr, lp.nxt WHILE lp#NIL DO
count ← count+1
ENDLOOP;
cp.lp ← o.ptr;
END;
xstr => cp.lp ← NIL;
ENDCASE =>
MiscDefs.CallDebugger["Can’t expand this ob type"];
cp.itemCount ← count;
IF name#NIL THEN cp.name ← name
ELSE FOR cl: LONG POINTER TO cList ← cellList, cl.nxt
WHILE cl#NIL DO
IF cl.ob=ob THEN {cp.name ← cl.name; EXIT};
ENDLOOP;
END;
RETURN[ob.auxPnt];
END; -- of MakeProto

origCifScale: PUBLIC INTEGER; -- centiMicrometers per lambda
lambdaRelativeCoordScale: PUBLIC Coord;
-- Coords per ppdefs.locNum
coordScale: PUBLIC ARRAY LocNumScale OF Coord;

SetCoordScale: PROCEDURE[] =
BEGIN -- from Chipmonk feedback window
origCifScale ← ppdddefs.pCifScale;
-- centiMicrometers per lambda
lambdaRelativeCoordScale ← -- to Coords = nanometers
(origCifScale*10)/Lambda;
coordScale ← -- to nanometers
[
lambdaRelative: lambdaRelativeCoordScale,
absolute: 250 -- looks like 0.5 um lambda
-- this may be overwritten later
];
END; -- of SetCoordScale


NullLpAux: PROCEDURE[lp: listPtr] =
BEGIN
WHILE lp#NIL DO
NullObAux[lp.ob];
lp ← lp.nxt;
ENDLOOP;
END;

NullObAux: PROCEDURE[ob: obPtr] =
BEGIN
ob.auxPnt ← NIL;
WITH o: ob SELECT FROM
cell => NullLpAux[o.ptr];
ENDCASE => NULL;
END;

-- Module START code

implantBeyondThinOx, cutPolyGap,
nPlusToPPlus, nWellToNPlus, pWellToPPlus,
viaCutGap: Coord;

NullLpAux[masterList];
SetCoordScale[];
implantBeyondThinOx ← ScaleFromChipmonk[(3*Lambda)/2];
cutPolyGap ← ScaleFromChipmonk[2*Lambda];
viaCutGap ← ScaleFromChipmonk[3*Lambda];
nPlusToPPlus ← ScaleFromChipmonk[3*Lambda];
nWellToNPlus ← ScaleFromChipmonk[5*Lambda];
pWellToPPlus ← ScaleFromChipmonk[5*Lambda];

END. -- of ChipExpandImpl