MarkBondingPads:
PUBLIC
PROC[cell: Core.CellType] ~ {
overGlass: CD.Layer ← CD.FetchLayer[tech, $ovg];
cut2: CD.Layer ← CD.FetchLayer[tech, $cut2];
layDeco: CoreGeometry.Decoration ← PWCore.extractMode.decoration;
ect: Core.CellType;
extractedToSource: RefTab.Ref;
layout: CD.Object;
bondingFrameSize: REF CD.Position;
fourteen: INT ← tech.lambda*14;
IsBig:
PROC[ob:
CD.Object]
RETURNS[isBig:
BOOL] = {
Ref [Cherry]<MPCCIF>7.0>XrVTI4x>CDMEBESCMOSB16Nov87.load:
oxidePad ← ((met2-10) AND (ovg OR cut2))-4
IF met2 always covers cut2 THEN (min dimension of cut2 > 14) => ovg
size: CD.Position ← CD.InterestSize[ob];
RETURN[size.x > fourteen AND size.y > fourteen]};
EachAtomic:
PROC[wire: Core.Wire] ~ {
sourceWire: Core.Wire ← NARROW[RefTab.Fetch[extractedToSource, wire].val];
instances: LIST OF CoreGeometry.Instance;
EachInst: CoreGeometry.EachInstanceProc ~ {
-- instance RETURNS quit
IF ~CDRects.IsBareRect[instance.obj]
THEN [] ← CoreGeometry.FlattenInstance[instance, EachInst]
ELSE {
IF instance.obj.layer=overGlass
OR
(instance.obj.layer=cut2 AND IsBig[instance.obj]) THEN
instances ← CONS[instance, instances]}};
name: IO.ROPE;
IF sourceWire=NIL THEN RETURN;
instances ← NARROW[CoreProperties.GetWireProp[sourceWire, $BondingPads]];
name ← CoreOps.GetFullWireName[cell.public, sourceWire];
[] ← CoreGeometry.EnumerateAllGeometry[layDeco, ect, wire, EachInst];
IF instances=NIL THEN TerminalIO.PutF["No pad for: %g\n",IO.rope[name]];
instances ← MergeSort[instances];
CoreProperties.PutWireProp[sourceWire, $BondingPads, instances]};
IF CoreProperties.GetCellTypeProp[cell, $BondingFrameSize]#NIL THEN RETURN;
[] ← PWCore.Layout[cell];
IF CoreProperties.GetCellTypeProp[cell, $BondingFrameSize]#NIL THEN RETURN;
[layout, ect, extractedToSource, ] ← PWCore.LayoutInfo[cell];
CoreOps.VisitRootAtomics[ect.public, EachAtomic];
bondingFrameSize ← NEW[CD.Position ← CD.InterestSize[layout]];
CoreProperties.PutCellTypeProp[cell, $BondingFrameSize, bondingFrameSize]};
GetPads:
PUBLIC
PROC[cell: Core.CellType]
RETURNS[padArray: PadArray] = {
size: CD.Position ← GetSize[cell];
cRect: CD.Rect ← [0, 0, size.x, size.y];
eachPublic:
PROC[wire: Core.Wire] = {
instances:
LIST
OF CoreGeometry.Instance ←
NARROW[CoreProperties.GetWireProp[wire, $BondingPads]];
FOR instances ← instances, instances.rest
WHILE instances#
NIL
DO
ir: CD.Rect ← CoreGeometry.BBox[instances.first];
side: Side ← NearestSide[ir, cRect];
offSet: CD.Position ← OffSet[ir, cRect, side];
pad: Pad ← [wire, offSet];
padArray[side].pads ← CONS[pad, padArray[side].pads] ENDLOOP };
Collect pads
[]𡤌oreOps.VisitRootAtomics[cell.public, eachPublic];
FOR side: Side
IN Side
DO
offSets: LIST OF INT ← NIL;
Find (and check) offsets
FOR pads: Pads ← padArray[side].pads, pads.rest
WHILE pads#
NIL
DO
offSets ← CONS[pads.first.pos.x, offSets];
FOR oSets:
LIST
OF
INT ← offSets, oSets.rest
WHILE oSets#
NIL
AND oSets.rest#
NIL
DO
TwoInts: TYPE = RECORD[i0, i1: INT];
IF oSets.first < oSets.rest.first THEN EXIT;
IF oSets.first = oSets.rest.first THEN {oSets.rest ← oSets.rest.rest; EXIT};
[oSets.first, oSets.rest.first] ← TwoInts[oSets.rest.first, oSets.first] ENDLOOP;
ENDLOOP;
padArray[side].offSets ← offSets;
IF offSets=NIL THEN LOOP;
IF offSets.rest#
NIL
THEN{
IF offSets.rest.rest#NIL THEN ERROR;
IF offSets.rest.first-offSets.first<100*tech.lambda THEN ERROR};
Sort by y then x
DO
done: BOOL ← TRUE;
FOR pads: Pads ← padArray[side].pads, pads.rest
WHILE pads#
NIL
AND pads.rest#
NIL
DO
TwoPads: TYPE = RECORD[p0, p1: Pad];
IF pads.first.pos.y < pads.rest.first.pos.y
THEN {
--IF (pads.rest.first.pos.y-pads.first.pos.y) < 100*tech.lambda THEN ERROR-- LOOP};
IF pads.first.pos.y > pads.rest.first.pos.y
OR pads.first.pos.x > pads.rest.first.pos.x
THEN
{[pads.first, pads.rest.first] ← TwoPads[pads.rest.first, pads.first]; done ← FALSE}
ENDLOOP;
IF done THEN EXIT ENDLOOP;
ENDLOOP};
MergeSort:
PROC[instances:
LIST
OF CoreGeometry.Instance]
RETURNS[LIST OF CoreGeometry.Instance] = {
TwoInstances: TYPE = RECORD[i1, i2: CoreGeometry.Instance];
DO
done: BOOL ← TRUE;
list: LIST OF CoreGeometry.Instance ← instances;
FOR list ← list, list.rest
WHILE list#
NIL
AND list.rest#
NIL
DO
ir1: CD.Rect ← CoreGeometry.BBox[list.first];
ir2: CD.Rect ← CoreGeometry.BBox[list.rest.first];
xr: CD.Rect ← CDBasics.Intersection[ir1, ir2];
touch: BOOL ← (xr.x2 >= xr.x1) AND (xr.y2 >= xr.y1);
IF touch
THEN {
union: CD.Rect ← CDBasics.Surround[ir1, ir2];
size: CD.Position ← CDBasics.SizeOfRect[union];
pos: CD.Position ← CDBasics.BaseOfRect[union];
newObj: CD.Object ← CDRects.CreateRect[size, list.first.obj.layer];
list.rest ← list.rest.rest;
list.first ← [newObj, [pos]];
done ← FALSE}
ELSE {
IF ~CompareRectBottomLeft[ir1, ir2]
THEN {[list.first, list.rest.first]←TwoInstances[list.rest.first, list.first]; done←FALSE}};
ENDLOOP;
IF done THEN EXIT ENDLOOP;
RETURN[instances]};
NearestSide:
PROC[sml, lrg:
CD.Rect]
RETURNS[side: Side ← left] ~ {
dist: INT ← ABS[lrg.x1 - sml.x1];
test: INT ← ABS[lrg.x2 - sml.x2]; IF test < dist THEN {dist ← test; side ← right};
test ← ABS[lrg.y1 - sml.y1]; IF test < dist THEN {dist ← test; side ← bottom};
test ← ABS[lrg.y2 - sml.y2]; IF test < dist THEN {dist ← test; side ← top}};
OffSet:
PROC[sml, lrg:
CD.Rect, side: Side]
RETURNS[offSet:
CD.Position] ~ {
The offSet when building a left side normalized set of pads. X is the distance in and y is the distance up.
offSet ←
SELECT side
FROM
left => [(sml.x1+sml.x2)/2 - lrg.x1, (sml.y1+sml.y2)/2],
right => [lrg.x2 - (sml.x1+sml.x2)/2, (sml.y1+sml.y2)/2],
bottom => [(sml.y1+sml.y2)/2 - lrg.y1, (sml.x1+sml.x2)/2],
top => [lrg.y2 - (sml.y1+sml.y2)/2, (sml.x1+sml.x2)/2],
ENDCASE => ERROR };