CIFIntPhase2.mesa
Copyright Ó 1985, 1987 by Xerox Corporation. All rights reserved.
Created by Jim Gasbarro March 12, 1985 12:38:00 pm PST
Last Edited by: Gasbarro, January 16, 1987 4:17:55 pm PST
McCreight, December 18, 1986 7:25:03 pm PST
Frank Bowers January 24, 1986 11:11:07 am PST
Last Edited by: Christian Jacobi, January 24, 1986 11:11:07 am PST
Bertrand Serlet May 21, 1987 4:37:46 pm PDT
DIRECTORY
Atom, Basics, CD, CDProperties, CDRects, CDCells, CDDirectory, CDOps, CDCurves, CDViewer, CMos, IntDefs, IntStorageDefs, IntTransDefs, IntUtilityDefs, IO, IODefs, OutputDefs, ParserTypeDefs, PolygonDefs, ReadCif, ReadCifUserCmd, Real, RealFns, Rope;
CIFIntPhase2: CEDAR PROGRAM
IMPORTS Atom, CD, CDProperties, CDRects, CDCells, CDDirectory, CDOps, CDCurves, CDViewer, IntTransDefs, IntStorageDefs, IntUtilityDefs, IO, IODefs, PolygonDefs, ReadCif, ReadCifUserCmd, Real, RealFns, Rope
EXPORTS IntDefs, OutputDefs, ReadCif =
BEGIN OPEN IntUtilityDefs, IntStorageDefs;
CIFMap: TYPE = RECORD [
size: NAT ← 0,
map: SEQUENCE maxSize: NAT OF CDCIFRelation
];
CDCIFRelation: TYPE = RECORD[
cifName: ATOM,
cdLevel: CD.Layer,
compensation: INT ← 0
];
cifMap: REF CIFMap;
CIFDestRec: TYPE = RECORD [ -- from BrandyCIFter.mesa, wasn't in an interface...
cifDest: Rope.ROPE,
deltaRadius: INT -- nanometers, + means cif is bigger
];
technology: PUBLIC ATOMNIL;
design: PUBLIC CD.Design ← NIL;
cdLambda: CD.Number ← 0;
cifLambda: CARDINAL ← 0;
unknownLayers: LIST OF ATOM ← NIL;
nanometersPerCifUnit: INT = 10;
nextCellNumber: INT ← 0;
numSides: CARDINAL ← 12;
ErrorMsgType: TYPE = ReadCifUserCmd.ErrorMsgType;
Map: PUBLIC PROCEDURE [layerName: Rope.ROPE] RETURNS [n: CARDINAL] =
BEGIN
cm: REF CIFMap;
ccr: REF CDCIFRelation ← NIL;
cifLayerAtom: ATOM = Atom.MakeAtom[layerName];
-- first time through, initialize data structures
IF cifMap = NIL THEN
BEGIN
cifMap ← NEW[CIFMap[1]];
cifMap.size ← 1;
IF CD.FetchTechnology[ReadCif.technology] = NIL THEN
{IODefs.WriteLine["Error: Chipndale technology not loaded"]; Abort[]};
IF design=NIL THEN {
design ← CDOps.CreateDesign[CD.FetchTechnology[ReadCif.technology]];
design.name ← ReadCif.designName;
};
cdLambda ← design.technology.lambda;
cifLambda ← ReadCif.cifUnitsPerLambda;
IF cifLambda < 1 THEN {IODefs.WriteLine["Error: CIF units per lambda is too small"]; Abort[]};
END;
--if layer is defined in map, return the mapped number
FOR n IN [0..cifMap.size) DO
IF cifMap[n].cifName = cifLayerAtom THEN RETURN;
ENDLOOP;
-- see if it's an unknown layer that's been seen before
FOR u: LIST OF ATOM ← unknownLayers, u.rest WHILE u#NIL DO
IF u.first = cifLayerAtom THEN RETURN[LAST[CARDINAL]];
ENDLOOP;
-- layer never seen before, see if there is a corresponding Chipndale Level
ccr ← FindCDLayer[layerName];
IF ccr = NIL THEN {
-- no corresponding Chipndale Level, add to unknownLayers
unknownLayers ← CONS[cifLayerAtom, unknownLayers];
IODefs.WriteLine[Rope.Cat["CIF layer ", layerName, " is not registered with ChipNDale, objects on this layer will be deleted"]];
RETURN[LAST[CARDINAL]];
};
-- layer was not in map, but was known to Chipndale, add to map
cm ← NEW[CIFMap[cifMap.size+1]]; -- make space for a new layer
cm.size ← cifMap.size;
FOR i: NAT IN [0..cifMap.size) DO
cm[i] ← cifMap[i];
ENDLOOP;
cifMap ← cm;
cifMap[cifMap.size] ← ccr^;
n ← cifMap.size;
cifMap.size ← cifMap.size+1;
END;
FindCDLayer: PROC [ cifLayer: Rope.ROPE ] RETURNS [ result: REF CDCIFRelation ← NIL ] = {
TryFinding: PROC [ ref: REF ANY, curCDLayer: REF CD.Layer ← NIL ] RETURNS [ result: REF CDCIFRelation ← NIL ] = {
IF ref # NIL THEN WITH ref SELECT FROM
lora: LIST OF REF ANY => {
result ← TryFinding[lora.first, curCDLayer];
IF result # NIL THEN RETURN;
result ← TryFinding[lora.rest, curCDLayer];
};
rel: REF CDCIFRelation =>
IF cifLayerAtom = rel.cifName THEN result ← rel;
cdr: REF CIFDestRec =>
IF cifLayer.Equal[cdr.cifDest] AND curCDLayer # NIL THEN
result ← NEW[CDCIFRelation ← [
cifName: cifLayerAtom,
cdLevel: curCDLayer^,
compensation: cdr.deltaRadius/nanometersPerCifUnit]];
rope: Rope.ROPE =>
IF cifLayer.Equal[rope] AND curCDLayer # NIL THEN
result ← NEW[CDCIFRelation ← [
cifName: cifLayerAtom,
cdLevel: curCDLayer^,
compensation: 0]];
ENDCASE => NULL;
};
cifLayerAtom: ATOM = Atom.MakeAtom[cifLayer];
result ← TryFinding[CDProperties.GetTechnologyProp[design.technology, $CDxCIFLayerRelations]];
IF result # NIL THEN RETURN;
For backward compatability
FOR l: LIST OF CD.Layer ← design.technology.usedLayers, l.rest WHILE l#NIL DO
result ← TryFinding[CDProperties.GetLayerProp[l.first, $CDxCIFName], NEW[CD.Layer ← l.first]];
IF result # NIL THEN RETURN;
ENDLOOP;
};
Instantiate: PUBLIC PROCEDURE [] =
BEGIN
ClearBinding: PROCEDURE[sym: STEntry] =
BEGIN
sym.bound ← FALSE;
END;
IncludeObjectsNotDrawn: PROCEDURE[sym: STEntry] =
BEGIN
IF NOT sym.bound THEN InstantiateSymbol[sym: sym, root: FALSE];
END;
CIFtoCDPosition: PROCEDURE[call: Call] RETURNS [position: CD.Position, orientation: CD.Orientation] =
BEGIN
a11, a21, a12, a22, a33: REAL;
IntTransDefs.Push[];
IntTransDefs.ApplyLocal[call.t];
IntTransDefs.Scale[cdLambda, cifLambda];
position ← LOOPHOLE[IntTransDefs.TransformPoint[0,0]];
IntTransDefs.Pop[];
a33 ← call.t.a33;
a11 ← call.t.a11/a33;
a21 ← call.t.a21/a33;
a12 ← call.t.a12/a33;
a22 ← call.t.a22/a33;
IF a11 # 0 THEN
BEGIN
SELECT TRUE FROM
a11>0 AND a22>0 => orientation ← original;
a11>0 AND a22<0 => orientation ← rotate180X;
a11<0 AND a22>0 => orientation ← mirrorX;
a11<0 AND a22<0 => orientation ← rotate180;
ENDCASE => ERROR;
END ELSE
BEGIN
SELECT TRUE FROM
a21>0 AND a12>0 => orientation ← rotate90X;
a21>0 AND a12<0 => orientation ← rotate270;
a21<0 AND a12>0 => orientation ← rotate90;
a21<0 AND a12<0 => orientation ← rotate270X;
ENDCASE => ERROR;
END;
RETURN[position, orientation];
END;
OrthogonalTransform: PROCEDURE[call: Call] RETURNS [BOOL] =
BEGIN -- checks transformation to make sure any rotation is a multiple of 90 deg
IF (call.t.a11 = 0 AND call.t.a22 = 0) OR (call.t.a21 = 0 AND call.t.a12 = 0) THEN RETURN[TRUE] ELSE RETURN[FALSE];
END;
InstantiateSymbol: PROCEDURE[sym: STEntry, root: BOOL] =
BEGIN
ReportError: ReadCifUserCmd.ReportErrorProc =
BEGIN
IODefs.WriteLine[r];
SELECT msgType FROM
FatalError => curCell.errorInSubCell ← TRUE;
Warning => curCell.warningInSubCell ← TRUE;
ENDCASE => ERROR;
END;
IncludePolygon: PROCEDURE[poly: Polygon] =
BEGIN
pd: PolygonDefs.PolygonDescriptor;
IncludeTrapezoid: PROCEDURE[lowerLeftX, lowerRightX, lowerY, upperLeftX, upperRightX, upperY: REAL] =
BEGIN
IF upperLeftX # lowerLeftX OR upperRightX # lowerRightX THEN
BEGIN
points: LIST OF CD.Position ← NIL;
ob: CD.Object;
offset: CD.Position;
IF ~curCell.warningInSubCell THEN ReportError["Non-rectilinear geometry", Warning];
points ← CONS[
[Real.Round[(lowerLeftX+cifMap[poly.layer].compensation)*cdLambda/cifLambda],
Real.Round[(lowerY+cifMap[poly.layer].compensation)*cdLambda/cifLambda]],
points];
points ← CONS[
[Real.Round[(lowerRightX-cifMap[poly.layer].compensation)*cdLambda/cifLambda],
Real.Round[(lowerY+cifMap[poly.layer].compensation)*cdLambda/cifLambda]],
points];
points ← CONS[
[Real.Round[(upperRightX-cifMap[poly.layer].compensation)*cdLambda/cifLambda],
Real.Round[(upperY-cifMap[poly.layer].compensation)*cdLambda/cifLambda]],
points];
points ← CONS[
[Real.Round[(upperLeftX+cifMap[poly.layer].compensation)*cdLambda/cifLambda],
Real.Round[(upperY-cifMap[poly.layer].compensation)*cdLambda/cifLambda]],
points];
[ob, offset] ← CDCurves.CreatePolygon[points, cifMap[poly.layer].cdLevel];
[] ← CDCells.IncludeOb[
design: IF curCell.cdCellObj = NIL THEN design ELSE NIL,
cell: curCell.cdCellObj,
ob: ob,
trans: [offset],
mode: dontResize];
END ELSE {
rect: CD.Object ← CDRects.CreateRect[
size: [Real.Round[(upperRightX-upperLeftX-2*cifMap[poly.layer].compensation)*cdLambda/cifLambda], Real.Round[(upperY-lowerY-2*cifMap[poly.layer].compensation)*cdLambda/cifLambda]],
l: cifMap[poly.layer].cdLevel];
ib: CD.Position ← CD.InterestBase[rect];
[] ← CDCells.IncludeOb[
design: IF curCell.cdCellObj = NIL THEN design ELSE NIL,
cell: curCell.cdCellObj,
ob: rect,
trans: [[ Real.Round[(upperLeftX+cifMap[poly.layer].compensation)*cdLambda/cifLambda]-ib.x, Real.Round[(lowerY+cifMap[poly.layer].compensation)*cdLambda/cifLambda]-ib.y]],
mode: dontResize];
}
END;
pd ← PolygonDefs.PolyCreate[];
FOR l: LIST OF ParserTypeDefs.Point ← poly.p.first, l.rest WHILE l#NIL DO
PolygonDefs.PolyVertex[polygon: pd, x: l.first.x, y: l.first.y];
ENDLOOP;
PolygonDefs.PolyGenerate[polygon: pd, outputTrapezoid: IncludeTrapezoid];
END;
IncludeWire: PROCEDURE[wire: Wire] =
BEGIN
OnAxis: PROC[p1, p2: ParserTypeDefs.Point] RETURNS[BOOL] =
BEGIN
IF p1.x = p2.x OR p1.y = p2.y THEN RETURN[TRUE] ELSE RETURN[FALSE];
END;
FOR l: LIST OF ParserTypeDefs.Point ← wire.p.first, l.rest WHILE l.rest#NIL DO
IF OnAxis[l.first, l.rest.first] THEN {
rect: CD.Object ← CDRects.CreateRect[
size: IF l.first.x = l.rest.first.x THEN
[(wire.width-2*cifMap[wire.layer].compensation)*cdLambda/cifLambda,
(ABS[l.first.y - l.rest.first.y] - 2*cifMap[wire.layer].compensation)*cdLambda/cifLambda]
ELSE
[(ABS[l.first.x - l.rest.first.x] - 2*cifMap[wire.layer].compensation)*cdLambda/cifLambda,
(wire.width-2*cifMap[wire.layer].compensation)*cdLambda/cifLambda],
l: cifMap[wire.layer].cdLevel];
ib: CD.Position ← CD.InterestBase[rect];
pos: CD.Position ← IF l.first.x = l.rest.first.x THEN
[(l.rest.first.x - (wire.width/2) + cifMap[wire.layer].compensation)*cdLambda/cifLambda,
((IF l.first.y < l.rest.first.y THEN l.first.y ELSE l.rest.first.y) + cifMap[wire.layer].compensation)*cdLambda/cifLambda]
ELSE
[((IF l.first.x < l.rest.first.x THEN l.first.x ELSE l.rest.first.x) + cifMap[wire.layer].compensation)*cdLambda/cifLambda,
(l.rest.first.y - (wire.width/2) + cifMap[wire.layer].compensation)*cdLambda/cifLambda];
[] ← CDCells.IncludeOb[
design: IF curCell.cdCellObj = NIL THEN design ELSE NIL,
cell: curCell.cdCellObj,
ob: rect,
trans: [[pos.x-ib.x, pos.y-ib.y]],
mode: dontResize]
}
ELSE
BEGIN
RealPoint: TYPE = RECORD[x,y: REAL];
vector, unitVector: RealPoint;
h0, h90, h180, h270: RealPoint;
length: REAL;
poly: IntStorageDefs.Polygon ← NEW[IntStorageDefs.PolygonRec];
poly.p ← NEW[ParserTypeDefs.PathRecord];
vector ← [l.rest.first.x-l.first.x, l.rest.first.y-l.first.y];
length ← RealFns.SqRt[vector.x*vector.x + vector.y*vector.y];
unitVector ← [vector.x/length, vector.y/length];
h0 ← [unitVector.x*wire.width/2, unitVector.y*wire.width/2];
h90 ← [-h0.y, h0.x];
h180 ← [-h90.y, h90.x];
h270 ← [-h180.y, h180.x];
poly.p.first ← CONS[[Real.Round[l.first.x+h270.x], Real.Round[l.first.y+h270.y]], poly.p.first];
poly.p.first ← CONS[[Real.Round[l.rest.first.x+h270.x], Real.Round[l.rest.first.y+h270.y]], poly.p.first];
poly.p.first ← CONS[[Real.Round[l.rest.first.x+h90.x], Real.Round[l.rest.first.y+h90.y]], poly.p.first];
poly.p.first ← CONS[[Real.Round[l.first.x+h90.x], Real.Round[l.first.y+h90.y]], poly.p.first];
poly.layer ← wire.layer;
IncludePolygon[poly];
END;
ENDLOOP;
BEGIN -- fix up the endpoints with flashes or boxes
prevSegOnAxis: BOOLEANTRUE;
nextSegOnAxis: BOOLEANFALSE;
flash: IntStorageDefs.Flash ← NEW[IntStorageDefs.FlashRec];
box: IntStorageDefs.Box ← NEW[IntStorageDefs.BoxRec];
flash.layer ← wire.layer;
flash.diameter ← wire.width;
box.layer ← wire.layer;
box.length ← wire.width;
box.width ← wire.width;
box.xRot ← 1;
box.yRot ← 0;
box.bb.left ← 0;
box.bb.bottom ← 0;
box.bb.right ← wire.width;
box.bb.top ← wire.width;
FOR l: LIST OF ParserTypeDefs.Point ← wire.p.first, l.rest WHILE l.rest#NIL DO
nextSegOnAxis ← OnAxis[l.first, l.rest.first];
IF prevSegOnAxis AND nextSegOnAxis THEN
BEGIN
box.center.x ← l.first.x;
box.center.y ← l.first.y;
IncludeBox[box];
END
ELSE
BEGIN
flash.center.x ← l.first.x;
flash.center.y ← l.first.y;
IncludeFlash[flash];
END;
prevSegOnAxis ← nextSegOnAxis;
REPEAT
FINISHED =>
BEGIN
IF prevSegOnAxis THEN
BEGIN
box.center.x ← l.first.x;
box.center.y ← l.first.y;
IncludeBox[box];
END
ELSE
BEGIN
flash.center.x ← l.first.x;
flash.center.y ← l.first.y;
IncludeFlash[flash];
END;
END;
ENDLOOP;
END;
END;
IncludeFlash: PROC [flash: Flash] =
BEGIN
theta: REAL ← 360.0/numSides;
poly: IntStorageDefs.Polygon ← NEW[IntStorageDefs.PolygonRec];
poly.p ← NEW[ParserTypeDefs.PathRecord];
FOR i: NAT IN [0..numSides) DO
poly.p.first ← CONS[[Real.Round[flash.diameter/2.0*RealFns.CosDeg[theta/2 + i*theta] + flash.center.x], Real.Round[flash.diameter/2.0*RealFns.SinDeg[theta/2 + i*theta] + flash.center.y]], poly.p.first];
ENDLOOP;
poly.layer ← flash.layer;
IncludePolygon[poly];
END;
IncludeMBox: PROC [box: MBox] =
BEGIN
rect: CD.Object ← CDRects.CreateRect[
size: [(box.bb.right-box.bb.left-2*cifMap[box.layer].compensation)*cdLambda/cifLambda, (box.bb.top-box.bb.bottom-2*cifMap[box.layer].compensation)*cdLambda/cifLambda],
l: cifMap[box.layer].cdLevel];
ib: CD.Position ← CD.InterestBase[rect];
[] ← CDCells.IncludeOb[
design: IF curCell.cdCellObj = NIL THEN design ELSE NIL,
cell: curCell.cdCellObj,
ob: rect,
trans: [[(box.bb.left+cifMap[box.layer].compensation)*cdLambda/cifLambda - ib.x, (box.bb.bottom+cifMap[box.layer].compensation)*cdLambda/cifLambda - ib.y]],
mode: dontResize];
END;
IncludeBox: PROC [box: Box] =
BEGIN
IF (box.xRot=0 AND box.yRot#0) OR (box.xRot#0 AND box.yRot=0) THEN
BEGIN
xLength: LONG CARDINALIF box.xRot#0 THEN box.length ELSE box.width;
yWidth: LONG CARDINALIF box.xRot#0 THEN box.width ELSE box.length;
rect: CD.Object ← CDRects.CreateRect[
size: [(xLength-2*cifMap[box.layer].compensation)*cdLambda/cifLambda, (yWidth-2*cifMap[box.layer].compensation)*cdLambda/cifLambda],
l: cifMap[box.layer].cdLevel];
ib: CD.Position ← CD.InterestBase[rect];
[] ← CDCells.IncludeOb[
design: IF curCell.cdCellObj = NIL THEN design ELSE NIL,
cell: curCell.cdCellObj,
ob: rect,
trans: [[(box.center.x-xLength/2+cifMap[box.layer].compensation)*cdLambda/cifLambda-ib.x, (box.center.y-yWidth/2+cifMap[box.layer].compensation)*cdLambda/cifLambda-ib.y]],
mode: dontResize]
END
ELSE ReportError["Only Manhatten boxes implemented", FatalError];
END;
pending: LIST OF Object ← LIST[sym.guts];
objectCount: INT ← 0;
curCell: Cell ← NEW[CellRec];
Cell: TYPE = REF CellRec;
CellRec: TYPE = RECORD [
cdCellObj: CD.Object,
name: Rope.ROPENIL,
errorInSubCell: BOOLEANFALSE,
warningInSubCell: BOOLEANFALSE];
IF NOT root THEN -- we are including a cell into the directory only, i.e. it is not an application, i.e. it does not appear on the screen
BEGIN
sym.expanded ← TRUE;
curCell.cdCellObj ← CDCells.CreateEmptyCell[];
curCell.name ← NIL;
END;
WHILE pending # NIL DO
WHILE pending.first # NIL DO
WITH pending.first.first SELECT FROM
call: Call =>
BEGIN
SELECT TRUE FROM
call.callee.bound =>
BEGIN
position: CD.Position;
orientation: CD.Orientation;
IF ~OrthogonalTransform[call] THEN ReportError[IO.PutFR["Cell %g called with non-orthogonal cell placement", IO.card[call.callee.symNumber]], FatalError];
[position, orientation] ← CIFtoCDPosition[call];
[] ← CDCells.IncludeOb[
design: IF curCell.cdCellObj = NIL THEN design ELSE NIL,
cell: curCell.cdCellObj,
ob: NARROW[call.callee.spare, Cell].cdCellObj, -- Obj REF is hung on spare
trans: [position, orientation],
mode: dontResize
];
curCell.errorInSubCell ← NARROW[call.callee.spare, Cell].errorInSubCell; -- propagate errors and warnings
curCell.warningInSubCell ← NARROW[call.callee.spare, Cell].warningInSubCell;
END;
call.callee.defined AND ~call.callee.expanded =>
BEGIN
call.callee.expanded ← TRUE;
pending.first ← CONS[curCell, pending.first]; -- push the current cell
curCell ← NEW[CellRec];
curCell.cdCellObj ← CDCells.CreateEmptyCell[]; -- get a new one
pending.first ← CONS[call.callee, pending.first]; -- CONS return symbol
pending ← CONS[call.callee.guts, pending]; -- CONS contents of cell
LOOP; -- don't pop the stack
END;
call.callee.expanded =>
ReportError[IO.PutFR["Cell %g calls itself, inner call ignored.", IO.int[call.callee.symNumber]], FatalError];
~call.callee.defined =>
ReportError[IO.PutFR["Cell %g is undefined, call ignored.", IO.int[call.callee.symNumber]], FatalError];
ENDCASE => ERROR;
END;
symbol: STEntry =>
BEGIN
prevCell: Cell ← curCell;
symbol.expanded ← FALSE; -- returning from symbol call
symbol.bound ← TRUE;
symbol.spare ← curCell; -- keep the obj ref on spare
IF curCell.name = NIL THEN curCell.name IO.PutFR["CifCell #%g", IO.int[nextCellNumber ← nextCellNumber + 1]];
IF curCell.errorInSubCell THEN ReportError[Rope.Cat["*** Error in ", curCell.name], FatalError];
IF curCell.warningInSubCell THEN ReportError[Rope.Cat["* Warning in ", curCell.name], Warning];
[] ← CDCells.ResizeCell[NIL, curCell.cdCellObj];
[] ← CDDirectory.Include[
design: design,
object: curCell.cdCellObj,
name: curCell.name];
pending.first ← pending.first.rest; -- remove called symbol
curCell ← NARROW[pending.first.first]; -- restore context
END;
box: Box =>
IF box.layer # LAST[CARDINAL] THEN IncludeBox[box];
box: MBox =>
IF box.layer # LAST[CARDINAL] THEN IncludeMBox[box];
flash: Flash =>
IF flash.layer # LAST[CARDINAL] THEN IncludeFlash[flash];
poly: Polygon =>
IF poly.layer # LAST[CARDINAL] THEN IncludePolygon[poly];
wire: Wire =>
IF wire.layer # LAST[CARDINAL] THEN IncludeWire[wire];
userOb: UserOb =>
ReportError["UserOb not defined", Warning];
userCmd: UserCmd =>
BEGIN
if last object on list (first cif command after a DefineStart) is a UserCmd = 9 then assume that it is the cell name
IF userCmd.command = 9 AND pending.first.rest = NIL THEN
curCell.name ← NARROW[userCmd.data]
ELSE
ReadCifUserCmd.ParseUserCmd[userCmd, curCell.cdCellObj, design, ReportError];
END;
ENDCASE => ERROR;
pending.first ← pending.first.rest;
objectCount ← objectCount+1;
IF objectCount MOD 1000 = 0 THEN
IODefs.PostIt[IO.PutFR["Objects read: %g", IO.int[objectCount]]];
ENDLOOP;
pending ← pending.rest;
ENDLOOP;
IF NOT root THEN -- we are including a cell into the directory only
BEGIN
sym.expanded ← FALSE;
sym.bound ← TRUE;
sym.spare ← curCell; -- keep the cd name on spare
IF curCell.name = NIL THEN curCell.name IO.PutFR["CifCell #%g", IO.int[nextCellNumber ← nextCellNumber + 1]];
IF curCell.errorInSubCell THEN ReportError[Rope.Cat["*** Error in ", curCell.name], FatalError];
IF curCell.warningInSubCell THEN ReportError[Rope.Cat["* Warning in ", curCell.name], Warning];
[] ← CDCells.ResizeCell[NIL, curCell.cdCellObj];
[] ← CDDirectory.Include[
design: design,
object: curCell.cdCellObj,
name: curCell.name];
END
END; -- InstantiateSymbol
MapSymbols[proc: ClearBinding]; -- clear symbol table
InstantiateSymbol[sym: rootSymbol, root: TRUE]; -- instantiate top level design
MapSymbols[proc: IncludeObjectsNotDrawn]; -- includes cells which are not drawn
IF CDViewer.ViewersOf[design]=NIL THEN [] ← CDViewer.CreateViewer[design: design];
END;
FinishOutput: PUBLIC PROCEDURE[] RETURNS[BOOL] =
BEGIN
cifMap ← NIL;
design ← NIL;
unknownLayers ← NIL;
nextCellNumber ← 0;
RETURN[TRUE];
END;
Abort: PROCEDURE[] =
BEGIN
[] ← FinishOutput[];
ERROR ABORTED;
END;
END.