CDStitchedViasImpl.mesa
Copyright © 1987 by Xerox Corporation. All rights reversed.
Created by: Christian Jacobi, March 23, 1987 12:37:36 pm PST;
Using actual creation code from Brian Preas
Last edited by: Christian Jacobi, March 23, 1987 2:33:09 pm PST
Semi technology dependent:
Does not import technology, but works correctly only for a certain
range of technologies.
DIRECTORY
CD, CDAtomicObjects, CDBasics, CDCells, CDEvents, CDLayers, CDProperties, CDRects, CDSimpleRules, CDSimpleRulesBackdoor, CDOps, LRUCache, RealOps;
CDStitchedViasImpl: CEDAR PROGRAM
IMPORTS CD, CDAtomicObjects, CDBasics, CDCells, CDEvents, CDLayers, CDOps, CDProperties, CDRects, CDSimpleRules, CDSimpleRulesBackdoor, LRUCache, RealOps =
BEGIN
Rules: TYPE = CDSimpleRules.Rules;
GetSimpleBigContact: PROC [size: CD.Position, layer1, layer2: CD.Layer] RETURNS [obj: CD.Object ← NIL] = {
tech: CD.Technology ← CD.LayerTechnology[layer1];
IF tech#NIL THEN
SELECT tech.key FROM
$cmosB => {
l1a: ATOMCD.LayerKey[layer1];
l2a: ATOMCD.LayerKey[layer2];
SELECT TRUE FROM
(l1a = $met2 AND l2a = $met) OR (l1a = $met AND l2a = $met2) =>
obj ← CDAtomicObjects.CreateAtomicOb[$C2LargeVia, size, tech];
(l1a = $pol AND l2a = $met) =>
obj ← CDAtomicObjects.CreateAtomicOb[$C2LargeSimpleCon, size, tech, layer1];
(l1a = $met AND l2a = $pol) =>
obj ← CDAtomicObjects.CreateAtomicOb[$C2LargeSimpleCon, size, tech, layer2];
ENDCASE => NULL;
};
ENDCASE => NULL
};
GetSingleViaForStitching: PROC [rules: Rules, size: CD.Position, layer1, layer2: CD.Layer] RETURNS [via: CD.Object ← NIL] = {
--this is semi technology dependent;
tech: CD.Technology ~ CD.LayerTechnology[layer1];
minBigContact: CD.Object ~ GetSimpleBigContact[[1, 1], layer1, layer2];
IF minBigContact=NIL OR tech=NIL THEN {
--no big contacts, must do it with small ones
via ← CDSimpleRules.Contact[rules, layer1, layer2]
}
ELSE { -- big contact exists, determine size to use
lambda: CD.Number ~ tech.lambda;
ctSize: CD.Position ~ CD.InterestSize[minBigContact];
IF ctSize.x <= size.x AND ctSize.y <= size.y THEN {
--use 2, 3, or 4 lambda square vias that give largest perimeter
perim2x2: CD.Number ~ RealOps.ModalRound[size.x/(6*lambda), RealOps.FixMode]*RealOps.ModalRound[size.y/(6*lambda), RealOps.FixMode]*8*lambda; -- 2x2 contacts go in a 6x6 square
perim3x3: CD.Number ~ RealOps.ModalRound[size.x/(7*lambda), RealOps.FixMode]*RealOps.ModalRound[size.y/(7*lambda), RealOps.FixMode]*12*lambda; -- 3x3 contacts go in a 7x7 square
perim4x4: CD.Number ~ RealOps.ModalRound[size.x/(8*lambda), RealOps.FixMode]*RealOps.ModalRound[size.y/(8*lambda), RealOps.FixMode]*16*lambda; -- 4x4 contacts go in a 8x8 square
SELECT TRUE FROM
perim4x4 >= perim2x2 AND perim4x4 >= perim3x3 =>
via ← GetSimpleBigContact[[8*lambda, 8*lambda], layer1, layer2];
perim3x3 >= perim2x2 AND perim3x3 >= perim4x4 =>
via ← GetSimpleBigContact[[7*lambda, 7*lambda], layer1, layer2];
perim2x2 >= perim4x4 AND perim2x2 >= perim3x3 =>
via ← GetSimpleBigContact[[6*lambda, 6*lambda], layer1, layer2];
ENDCASE => ERROR;
}
ELSE { -- big contact too big, must do it with small ones
via ← CDSimpleRules.Contact[rules, layer1, layer2]
}
}
};
MinDist: PROC [rules: Rules, layer1, layer2: CD.Layer] RETURNS [m: CD.Number←-1] = {
--sorry: halfway technology dependent
-- assumes contact exists
-- assumes contact is atomic object
minCt: CD.Object = CDSimpleRules.Contact[rules, layer1, layer2];
ap: CDAtomicObjects.AtomicObsSpecific = NARROW[minCt.specific];
layer1 ← CDLayers.AbstractToPaint[layer1];
layer2 ← CDLayers.AbstractToPaint[layer2];
FOR dl: CDAtomicObjects.DrawList ← ap.rList, dl.rest WHILE dl#NIL DO
IF ~CDBasics.Inside[dl.first.r, ap.ir] THEN LOOP; --ignore wells
IF dl.first.layer=layer1 OR dl.first.layer=layer2 THEN LOOP; --ignore layer1, layer2
m ← MAX[m, CDSimpleRules.MinWidth[rules, dl.first.layer] +
CDSimpleRules.MinSpace[rules, dl.first.layer, dl.first.layer]];
ENDLOOP;
IF m<1 OR m>1000--catch in case of non implementation-- THEN ERROR;
};
InternalStitchedVia: PROC [rules: Rules, size: CD.Position, layer1, layer2: CD.Layer] RETURNS [via: CD.Object] = {
Incl: PROC [cell: CD.Object, ob: CD.Object, iPos: CD.Position←[0, 0]] = {
[] ← CDCells.IncludeOb[cell: cell, ob: ob, trans: [CDBasics.SubPoints[iPos, CD.InterestBase[ob]]], mode: dontResize];
};
contact: CD.Object ← GetSingleViaForStitching[rules, size, layer1, layer2];
ctSize: CD.Position ← CD.InterestSize[contact];
IF ctSize.x >= size.x AND ctSize.y >= size.y THEN via ← contact
ELSE {
tech: CD.Technology ~ CD.LayerTechnology[layer1];
minDist: CD.Number ← MinDist[rules, layer1, layer2];
grid: CD.Number ← IF tech#NIL THEN tech.lambda ELSE 1;
step: CD.Position ← [MAX[minDist, ctSize.x], MAX[minDist, ctSize.y]];
numY: INTMAX[1, size.y/step.y];
numX: INTMAX[1, size.x/step.x];
ctCov: CD.Position ← [(numX-1)*step.x+ctSize.x, (numY-1)*step.y+ctSize.y];
off: CD.Position ← [
(MAX[size.x-ctCov.x, 0]/(2*grid))*grid,
(MAX[size.y-ctCov.y, 0]/(2*grid))*grid
];
via ← CDCells.CreateEmptyCell[];
FOR indexY: CD.Number IN [0 .. numY) DO
FOR indexX: CD.Number IN [0 .. numX) DO
Incl[via, contact, [off.x+indexX*step.x, off.y+indexY*step.y]];
ENDLOOP;
ENDLOOP;
Incl[via, CDRects.CreateRect[size, layer1]];
Incl[via, CDRects.CreateRect[size, layer2]];
CDCells.ToSequenceMode[via];
[] ← CDCells.ResizeCell[NIL, via];
CDProperties.PutObjectProp[via, $CreatedBy, $StitchedVias];
IF ~CDOps.MakeImmutable[via] THEN ERROR;
};
};
DescRep: TYPE = RECORD [size: CD.Position, layer1, layer2: CD.Layer, ob: CD.Object←NIL, rules: Rules];
--Convention: layer1, layer2 are ordered!
cache: LRUCache.Handle ← LRUCache.Create[17, Hash, Equal];
Hash: PROC [x: REF] RETURNS [h: CARDINAL] = {
--it doesn't really matter whether the hash function is very good
d: REF DescRep = NARROW[x];
h ← (d.size.x MOD 10000B)*3+(d.size.y MOD 1000B)*19+d.layer1+d.layer2*13
--layer1, layer2 are ordered
};
Equal: PROC [x, y: REF] RETURNS [BOOL] = {
d1: REF DescRep = NARROW[x];
d2: REF DescRep = NARROW[y];
RETURN [d1.size=d2.size AND d1.layer1=d2.layer1 AND d1.layer2=d2.layer2 AND d1.rules=d2.rules]
--layer1, layer2 are ordered
};
StitchedVia: PROC [rules: Rules, design: CD.Design, size: CD.Position, l1, l2: CD.Layer] RETURNS [via: CD.Object←NIL] = {
d: REF DescRep ← NEW[DescRep←[
size: size,
layer1: MIN[l1, l2],
layer2: MAX[l1, l2],
rules: CDSimpleRules.GetRulesKey[rules]
]];
d ← NARROW[LRUCache.Include[cache, d].used];
IF d.ob#NIL THEN RETURN [via ← d.ob];
BEGIN --not found with exact size
new: CD.Object ← InternalStitchedVia[size: size, layer1: l1, layer2: l2, rules: rules];
IF new=NIL OR size=CD.InterestSize[new] THEN RETURN [via ← d.ob ← new]
ELSE {
--size was not exact
d1: REF DescRep ← NEW[DescRep←[
size: CD.InterestSize[new],
layer1: d.layer1,
layer2: d.layer2,
rules: d.rules
]];
d1 ← NARROW[LRUCache.Include[cache, d1].used];
IF d1.ob#NIL THEN RETURN [via ← d.ob ← d1.ob]; --discard new to increase sharing
RETURN [via ← d.ob ← d1.ob ← new];
};
END;
--if we want to introduce caching per design, use cache ← CDValue.Fetch[...
};
EachTechnology: CD.TechnologyEnumerator = {
SELECT tech.key FROM
$cmosB, $CMosA, $NMosA =>
CDSimpleRulesBackdoor.RegisterRules[[
key: NIL,
technology: tech,
largeContact: StitchedVia
]];
ENDCASE => NULL;
};
RegisterTechnology: CDEvents.EventProc = {
[] ← EachTechnology[NARROW[x]]
};
CDEvents.RegisterEventProc[$RegisterTechnology, RegisterTechnology];
[] ← CD.EnumerateTechnologies[EachTechnology];
END.