CifToCDImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Ch. LeCocq, September 14, 1987
Christian Le Cocq July 13, 1988 4:30:04 pm PDT
Last Edited by: Gasbarro May 4, 1988 10:19:24 am PDT
Converts Cif format data into ChipNDale cells. Previous code has been very helpful. It has been written by : Frank Bowers, Jim Gasbarro, Christian Jacobi, Ed McCreight, Martin Newell, Bertrand Serlet, and probably others who didn't put their name on top of the file in the begining of the ages.
DIRECTORY
Basics,
CD,
CDBasics,
CDCells,
CDCurves,
CDDirectory,
CDRects,
CDSymbolicObjects,
CGArea,
CGClipper,
CGReducer,
CIFParser,
CifToCD,
Convert,
GraphicsBasic,
IntHashTable,
IO,
Real,
RealFns,
RefTab,
Rope,
RuntimeError,
SymTab,
TerminalIO;
CifToCDImpl: CEDAR PROGRAM
IMPORTS
CD,
CDBasics,
CDCells,
CDCurves,
CDDirectory,
CDRects,
CDSymbolicObjects,
CGArea,
CGClipper,
CGReducer,
CIFParser,
Convert,
IntHashTable,
IO,
Real,
RealFns,
RefTab,
Rope,
RuntimeError,
SymTab,
TerminalIO
EXPORTS CifToCD
~ BEGIN
external types
PolygonDescriptor: TYPE ~ CGReducer.Ref;
internal types
ReadCifHandle: TYPE ~ REF ReadCifHandleRec;
ReadCifHandleRec: TYPE ~ RECORD[
design: CD.Design,
basicTransf: CD.Transformation,
curObj: CifObject ← NIL,
curLayerData: LayerData ← NIL,
prevLayerData: LayerData ← NIL,
layerTable: SymTab.Ref,
symNo: CARDLAST[CARD],
mult: CARD ← 1,
div: CARD ← 1,
cifPerLambda: INT ← 0,
symbolTable: IntHashTable.Table,
commented: BOOLEAN
];
LayerData: TYPE ~ REF LayerDataRec;
LayerDataRec: TYPE ~ RECORD[
layer: CD.Layer,
compensation: INT ← 0
];
CifObject: TYPE ~ REF CifObjectRec;
CifObjectRec: TYPE ~ RECORD[
ob: CD.Object,
name: Rope.ROPENIL,
undefSymb: LIST OF CARDNIL,
included,
fullyDefined,
instantiated: BOOLEANFALSE
];
global variables
registredTables: RefTab.Ref ← RefTab.Create[]; -- table of the CIF to CD layer tables
numSides: NAT ← 12; --number of sides of the "round" flash polygon
verbose: BOOLEANFALSE; --debugging printout
Polygons
PolyCreate: PROC RETURNS [polygon: PolygonDescriptor] ~ {
Create new polygon
huge: REAL ← 1.0E20;
clipper: CGClipper.Ref ← CGClipper.New[size: 4];
CGClipper.SetBox[self: clipper, box: [xmin: -huge, ymin: -huge, xmax: huge, ymax: huge]];
polygon ← CGReducer.New[size: 4];
CGClipper.Load[self: clipper, reducer: polygon];
};
PolyVertex: PROC [polygon: PolygonDescriptor, x, y: REAL] =
Add vertex to polygon
{CGReducer.Vertex[self: polygon, v: [x: x, y: y]]};
PolyGenerate: PROC[polygon: PolygonDescriptor, outputTrapezoid: PROC[llx, lrx, ly, ulx, urx, uy: REAL]] ~ {
Generate the polygon defined up to last PolyVertex
tiling: CGArea.Ref = CGArea.New[size: 4];
CGReducer.Close[polygon];
CGReducer.Generate[self: polygon, area: tiling];
UNTIL CGArea.Empty[tiling] DO
t: GraphicsBasic.Trap = CGArea.Remove[tiling];
outputTrapezoid[llx: t.xbotL, lrx: t.xbotR, ly: t.ybot, ulx: t.xtopL, urx: t.xtopR, uy: t.ytop];
ENDLOOP;
};
Layer Tables
GetLayerTable: PROC [regKey: ATOM] RETURNS [table: SymTab.Ref] ~ {
found: BOOLEAN;
val: RefTab.Val;
[found, val] ← RefTab.Fetch[registredTables, regKey];
IF found THEN RETURN[NARROW[val, SymTab.Ref]];
table ← SymTab.Create[];
[] ← RefTab.Store[registredTables, regKey, table];
};
RegisterLayer: PUBLIC PROC [regKey: ATOM, cifName: Rope.ROPE, cdLayer: CD.Layer, compensation: INT ← 0] RETURNS [found: BOOLEAN] ~ {
layerTable: SymTab.Ref ← GetLayerTable[regKey];
IF cdLayer=CD.undefLayer THEN found ← SymTab.Delete[layerTable, cifName]
ELSE found ← NOT SymTab.Store[layerTable, cifName, NEW[LayerDataRec ← [cdLayer, compensation]]];
};
GetLayerData: PROC [layerTable: SymTab.Ref, cifName: Rope.ROPE] RETURNS [layerData: LayerData] ~ {
found: BOOLEAN;
val: SymTab.Val;
[found, val] ← SymTab.Fetch[layerTable, cifName];
IF found THEN RETURN[NARROW[val, LayerData]]
ELSE CIFParser.ClientError[Rope.Concat["No registration for layer ", cifName]]
};
Misc...
NewCifObject: PROC [i: CARD, readH: ReadCifHandle] RETURNS [obj: CifObject] ~ {
obj ← NEW [CifObjectRec];
obj.ob ← CDCells.CreateEmptyCell[];
IF NOT IntHashTable.Store[readH.symbolTable, i, obj] THEN ERROR; -- implementation bug
};
IncludeAll: PROC [obj: CifObject, readH: ReadCifHandle] ~ {
IF obj.included THEN RETURN;
UNTIL obj.undefSymb=NIL DO
son: CifObject ← NARROW[IntHashTable.Fetch[readH.symbolTable, obj.undefSymb.first].value];
IncludeAll[son, readH];
obj.undefSymb ← obj.undefSymb.rest;
ENDLOOP;
[] ← CDCells.ResizeCell[NIL, obj.ob];
[] ← CDDirectory.Include[design: readH.design, object: obj.ob, name: obj.name];
obj.included ← TRUE;
};
IncludeOb: PROC [ob: CD.Object, trans: CD.Transformation, readH: ReadCifHandle] ~ {
IF readH.curObj = NIL THEN [] ← CDCells.IncludeOb[
design: readH.design,
cell: NIL,
ob: ob,
trans: CDBasics.ComposeTransform[trans, readH.basicTransf],
mode: dontNotify
]
ELSE [] ← CDCells.IncludeOb[
design: NIL,
cell: readH.curObj.ob,
ob: ob,
trans: trans,
mode: dontResize
];
};
CIFtoCDPosition: PROC[m: CIFParser.TMatrix, mult, div: INT] RETURNS [transf: CD.Transformation] = {
newOr: CIFParser.Point ← CIFParser.TransformPt[m, [0, 0]];
transf.off ← [newOr.x*mult/div, newOr.y*mult/div];
IF m.a11 # 0.0 THEN {
SELECT TRUE FROM
m.a11>0.0 AND m.a22>0.0 => transf.orient ← original;
m.a11>0.0 AND m.a22<0.0 => transf.orient ← rotate180X;
m.a11<0.0 AND m.a22>0.0 => transf.orient ← mirrorX;
m.a11<0.0 AND m.a22<0.0 => transf.orient ← rotate180;
ENDCASE => ERROR;
}
ELSE {
SELECT TRUE FROM
m.a21>0.0 AND m.a12>0.0 => transf.orient ← rotate90X;
m.a21>0.0 AND m.a12<0.0 => transf.orient ← rotate270;
m.a21<0.0 AND m.a12>0.0 => transf.orient ← rotate90;
m.a21<0.0 AND m.a12<0.0 => transf.orient ← rotate270X;
ENDCASE => ERROR;
};
};
OnAxis: PROC[p1, p2: CIFParser.Point] RETURNS[BOOL] = {
RETURN[p1.x = p2.x OR p1.y = p2.y];
};
CIF commands interpretation
DefDelete: PROC[i: CARD, data: REF ANY] ~ {
KillBiggerThanI: PROC [key: IntHashTable.Key, value: IntHashTable.Value] RETURNS [quit: BOOLEANFALSE] ~ {
IntHashTable.EachPairAction
IF key>=INT[i] THEN [] ← IntHashTable.Delete[readH.symbolTable, key];
};
readH: ReadCifHandle ~ NARROW[data];
[] ← IntHashTable.Pairs[readH.symbolTable, KillBiggerThanI]
};
DefStart: PROC[i, a, b: CARD, data: REF ANY] ~ {
readH: ReadCifHandle ~ NARROW[data];
IF readH.symNo#LAST[CARD] THEN ERROR; -- internal check
readH.curObj ← NARROW[IntHashTable.Fetch[readH.symbolTable, i].value];
IF readH.curObj#NIL THEN {
IF readH.curObj.fullyDefined THEN {
readH.curObj.ob ← CDCells.CreateEmptyCell[];
TerminalIO.PutF["***Warning: Symbol #%d already defined, old symbol erased\n", IO.card[i]];
};
}
ELSE readH.curObj ← NewCifObject[i, readH];
readH.curObj.fullyDefined ← TRUE;
readH.symNo ← i;
readH.mult ← a;
readH.div ← b;
readH.prevLayerData ← readH.curLayerData; -- push the global level layer
readH.curLayerData ← NIL; -- a layer should be specified inside each symbol
};
DefFinish: PROC[data: REF ANY] ~ {
readH: ReadCifHandle ~ NARROW[data];
IF readH.curObj.undefSymb=NIL THEN IncludeAll[readH.curObj, readH];
readH.curLayerData ← readH.prevLayerData; --pop the global level layer
readH.curObj ← NIL;
readH.symNo ← LAST[CARD]; -- to allow to flag nested DSs (should be caught by the parser)
readH.mult ← 1;
readH.div ← 1;
};
Polygon: PROC[p: CIFParser.Path, data: REF ANY] ~ {
IncludeTrapezoid: PROC[llx, lrx, ly, ulx, urx, uy: REAL] = {
IF ulx # llx OR urx # lrx THEN {
points: LIST OF CD.Position ← NIL;
ob: CD.Object;
offset: CD.Position;
IF ~curCell.warningInSubCell THEN TerminalIO.PutRope["Non-rectilinear geometry", Warning];
points ← CONS[[Real.Round[(llx+compensation)*cdpl/cifpl], Real.Round[(ly+compensation)*cdpl/cifpl]], points];
points ← CONS[[Real.Round[(lrx-compensation)*cdpl/cifpl], Real.Round[(ly+compensation)*cdpl/cifpl]], points];
points ← CONS[[Real.Round[(urx-compensation)*cdpl/cifpl], Real.Round[(uy-compensation)*cdpl/cifpl]], points];
points ← CONS[[Real.Round[(ulx+compensation)*cdpl/cifpl], Real.Round[(uy-compensation)*cdpl/cifpl]], points];
[ob, offset] ← CDCurves.CreatePolygon[points, layer];
IncludeOb[ob, [offset], readH];
}
ELSE {
rect: CD.Object ← CDRects.CreateRect[
size: [Real.Round[(urx-ulx-2*compensation)*cdpl/cifpl], Real.Round[(uy-ly-2*compensation)*cdpl/cifpl]],
l: layer];
ib: CD.Position ← CD.InterestBase[rect];
IncludeOb[rect, [[Real.Round[(ulx+compensation)*cdpl/cifpl]-ib.x, Real.Round[(ly+compensation)*cdpl/cifpl]-ib.y]], readH];
}
};
readH: ReadCifHandle ~ NARROW[data];
pd: PolygonDescriptor;
cdpl, cifpl, compensation: INT;
layer: CD.Layer;
IF readH.curLayerData=NIL THEN CIFParser.ClientError["undefined layer for polygon"];
compensation ← readH.curLayerData.compensation;
layer ← readH.curLayerData.layer;
cdpl ← readH.design.technology.lambda*readH.mult;
cifpl ← readH.cifPerLambda*readH.div;
pd ← PolyCreate[];
FOR l: CIFParser.Path ← p, l.rest WHILE l#NIL DO
PolyVertex[polygon: pd, x: l.first.x, y: l.first.y];
ENDLOOP;
PolyGenerate[polygon: pd, outputTrapezoid: IncludeTrapezoid];
};
Box: PROC[l, w: CARD, c, d: CIFParser.Point, data: REF ANY] ~ {
readH: ReadCifHandle ~ NARROW[data];
cdpl, cifpl, compensation: INT;
layer: CD.Layer;
IF readH.curLayerData=NIL THEN CIFParser.ClientError["undefined layer for box"];
compensation ← readH.curLayerData.compensation;
cdpl ← readH.design.technology.lambda*readH.mult;
cifpl ← readH.cifPerLambda*readH.div;
layer ← readH.curLayerData.layer;
IF (d.x=0 AND d.y#0) OR (d.x#0 AND d.y=0) THEN {
xLength: CARDIF d.x#0 THEN l ELSE w;
yWidth: CARDIF d.x#0 THEN w ELSE l;
rect: CD.Object ← CDRects.CreateRect[
size: [(xLength-2*compensation)*cdpl/cifpl,
(yWidth-2*compensation)*cdpl/cifpl],
l: layer];
ib: CD.Position ← CD.InterestBase[rect];
IncludeOb[rect, [[(c.x-xLength/2+compensation)*cdpl/cifpl-ib.x,
(c.y-yWidth/2+compensation)*cdpl/cifpl-ib.y]], readH];
}
ELSE CIFParser.ClientError["Only Manhatan boxes implemented"];
};
RoundFlash: PROC[d: CARD, c: CIFParser.Point, data: REF ANY] ~ {
readH: ReadCifHandle ~ NARROW[data];
theta: REAL ← 360.0/numSides;
p: CIFParser.Path;
FOR i: NAT IN [0..numSides) DO
p ← CONS[[Real.Round[d/2.0*RealFns.CosDeg[theta/2 + i*theta] + c.x],
Real.Round[d/2.0*RealFns.SinDeg[theta/2 + i*theta] + c.y]], p];
ENDLOOP;
Polygon[p, data];
};
Wire: PROC[w: CARD, p: CIFParser.Path, data: REF ANY] ~ {
readH: ReadCifHandle ~ NARROW[data];
cdpl, cifpl, compensation: INT;
layer: CD.Layer;
IF readH.curLayerData=NIL THEN CIFParser.ClientError["undefined layer for wire"];
compensation ← readH.curLayerData.compensation;
layer ← readH.curLayerData.layer;
cdpl ← readH.design.technology.lambda*readH.mult;
cifpl ← readH.cifPerLambda*readH.div;
FOR l: CIFParser.Path ← p, 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 [(w-2*compensation)*cdpl/cifpl, (ABS[l.first.y-l.rest.first.y]-2*compensation)*cdpl/cifpl]
ELSE [(ABS[l.first.x-l.rest.first.x]-2*compensation)*cdpl/cifpl, (w-2*compensation)*cdpl/cifpl],
l: layer];
ib: CD.Position ← CD.InterestBase[rect];
pos: CD.Position ← IF l.first.x=l.rest.first.x THEN [(l.rest.first.x-(w/2) + compensation)*cdpl/cifpl, ((IF l.first.y < l.rest.first.y THEN l.first.y ELSE l.rest.first.y) + compensation)*cdpl/cifpl]
ELSE [((IF l.first.x < l.rest.first.x THEN l.first.x ELSE l.rest.first.x) + compensation)*cdpl/cifpl, (l.rest.first.y - (w/2) + compensation)*cdpl/cifpl];
IncludeOb[rect, [[pos.x-ib.x, pos.y-ib.y]], readH];
}
ELSE {
RealPoint: TYPE = RECORD[x, y: REAL];
vector, unitVector: RealPoint;
h0, h90, h180, h270: RealPoint;
length: REAL;
p: CIFParser.Path;
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*w/2, unitVector.y*w/2];
h90 ← [-h0.y, h0.x];
h180 ← [-h90.y, h90.x];
h270 ← [-h180.y, h180.x];
p ← CONS[[Real.Round[l.first.x+h270.x], Real.Round[l.first.y+h270.y]], p];
p ← CONS[[Real.Round[l.rest.first.x+h270.x], Real.Round[l.rest.first.y+h270.y]], p];
p ← CONS[[Real.Round[l.rest.first.x+h90.x], Real.Round[l.rest.first.y+h90.y]], p];
p ← CONS[[Real.Round[l.first.x+h90.x], Real.Round[l.first.y+h90.y]], p];
Polygon[p, readH];
};
ENDLOOP;
{ -- fix up the endpoints with flashes or boxes
prevSegOnAxis: BOOLEANTRUE;
nextSegOnAxis: BOOLEANFALSE;
FOR l: CIFParser.Path ← p, l.rest WHILE l.rest#NIL DO
nextSegOnAxis ← OnAxis[l.first, l.rest.first];
IF prevSegOnAxis AND nextSegOnAxis THEN Box[w, w, l.first, [1, 0], data]
ELSE RoundFlash[w, l.first, data];
prevSegOnAxis ← nextSegOnAxis;
REPEAT
FINISHED => IF prevSegOnAxis THEN Box[w, w, l.first, [1, 0], data]
ELSE RoundFlash[w, l.first, data]
ENDLOOP;
};
};
Layer: PROC[n: Rope.ROPE, data: REF ANY] ~ {
readH: ReadCifHandle ~ NARROW[data];
readH.curLayerData ← GetLayerData[readH.layerTable, n];
};
Call: PROC[s: CARD, t: CIFParser.Transformation, data: REF ANY] ~ {
readH: ReadCifHandle ~ NARROW[data];
obj: CifObject;
transf: CD.Transformation;
cdpl: INT ← readH.design.technology.lambda*readH.mult;
cifpl: INT ← readH.cifPerLambda*readH.div;
m: CIFParser.TMatrix ← CIFParser.TransfToMatrix[t];
IF ~CIFParser.IsOrthogonalTransform[m] THEN CIFParser.ClientError["Cell called with non-orthogonal cell placement"];
transf ← CIFtoCDPosition[m, cdpl, cifpl];
obj ← NARROW[IntHashTable.Fetch[readH.symbolTable, s].value];
IF obj=NIL THEN {
obj ← NewCifObject[s, readH];
readH.curObj.undefSymb ← CONS[s, readH.curObj.undefSymb];
IF verbose THEN TerminalIO.PutF[" Symbol %d called in definition of %d before being defined\n", IO.int[s], IO.int[readH.symNo]];
};
IF readH.curObj = NIL THEN IncludeAll[obj, readH];
IncludeOb[obj.ob, transf, readH];
};
UserExtension: PROC[u: CARD, t: Rope.ROPE, data: REF ANY] ~ {
ENABLE IO.Error, IO.EndOfStream, RuntimeError.BoundsFault => GOTO Abort; --punt if we don't understand the syntax
readH: ReadCifHandle ~ NARROW[data];
lastCharIndex: NAT ← Rope.Length[t]-1;
UNTIL Rope.Fetch[t, lastCharIndex]#' DO --skip trailing blanks
lastCharIndex ← lastCharIndex-1;
ENDLOOP;
SELECT TRUE FROM
u=9 AND NOT Rope.Fetch[t, 0]='4 =>
-- cell name syntax: 9 RamCell;
IF readH.curObj.name = NIL THEN readH.curObj.name ← Rope.Substr[t, 1, lastCharIndex];
u=9 AND Rope.Fetch[t, 0]='4 => {
-- signal name syntax: 94 Vdd 268 -8 CM1;
MyTokenProc: IO.BreakProc = {
-- accepts +, -, and ← as other
RETURN [SELECT char FROM
'[, '], '(, '), '{, '}, '", '*, '/, '@ => break, -- they could be part of a name: {[43][5]}
IN [IO.NUL .. IO.SP] => sepr,
',, ':, '; => sepr,
ENDCASE => other];
};
ris: IO.STREAMIO.RIS[t];
junk: Rope.ROPEIO.GetTokenRope[ris, MyTokenProc].token;
name: Rope.ROPEIO.GetTokenRope[ris, MyTokenProc].token;
xPos: INT ← Convert.IntFromRope[IO.GetTokenRope[ris, MyTokenProc].token];
yPos: INT ← Convert.IntFromRope[IO.GetTokenRope[ris, MyTokenProc].token];
layer: CD.Layer ← GetLayerData[readH.layerTable, IO.GetTokenRope[ris, MyTokenProc].token].layer;
cdpl, cifpl: INT;
cdpl ← readH.design.technology.lambda*readH.mult;
cifpl ← readH.cifPerLambda*readH.div;
xPos ← xPos*cdpl/cifpl;
yPos ← yPos*cdpl/cifpl;
[] ← CDCells.IncludeInstance[
design: readH.design,
cell: readH.curObj.ob,
inst: CDSymbolicObjects.CreateSymInst[
name: name,
denotes: [xPos, yPos, xPos, yPos],
layer: layer
],
mode: dontResize
]
};
ENDCASE => TerminalIO.PutF["Unknown User Cmd #%d, content:%g\n", IO.card[u], IO.rope[t]];
EXITS
Abort =>
TerminalIO.PutF["Can't parse User Cmd #%d, content:%g\n", IO.card[u], IO.rope[t]];
};
Comment: PROC[c: Rope.ROPE, data: REF ANY] ~ {
readH: ReadCifHandle ~ NARROW[data];
IF readH.commented THEN TerminalIO.PutRopes["CIF comment: ", c, "\n"];
};
ReadFile: PUBLIC PROC [cifFile: IO.STREAM, design: CD.Design, regKey: ATOM, basicTransf: CD.Transformation ← [], cifPerLambda: INT ← 100, commented: BOOLEANFALSE] RETURNS [errMsg: Rope.ROPE] ~ {
readH: ReadCifHandle ← NEW[ReadCifHandleRec ← [
design: design,
basicTransf: basicTransf,
layerTable: GetLayerTable[regKey],
cifPerLambda: cifPerLambda,
symbolTable: IntHashTable.Create[],
commented: commented
]];
readReg: CIFParser.Registration ← NEW[CIFParser.RegistrationRec ← [
defDelete: DefDelete,
defStart: DefStart,
defFinish: DefFinish,
polygon: Polygon,
box: Box,
roundFlash: RoundFlash,
wire: Wire,
layer: Layer,
call: Call,
userExtension: UserExtension,
comment: Comment,
data: readH
]];
CIFParser.Parse[cifFile, readReg ! CIFParser.Error => {
errMsg ← IO.PutFR["%g @ %d\n", IO.rope[msg], IO.int[IO.GetIndex[cifFile]]];
GOTO Exit;
}];
EXITS Exit => {};
};
END.