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:
BOOLEAN ←
FALSE] ~ {
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: CARD ← IF d.x#0 THEN l ELSE w;
yWidth: CARD ← IF 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: BOOLEAN ← TRUE;
nextSegOnAxis: BOOLEAN ← FALSE;
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
UserExtensionProc:
PROC [u:
CARD, t: Rope.
ROPE, data:
REF
ANY] ~ {
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.STREAM ← IO.RIS[t];
junk: Rope.ROPE ← IO.GetTokenRope[ris, MyTokenProc].token;
name: Rope.ROPE ← IO.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]];
};
UserExtensionProc[u, t, data];
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:
BOOLEAN ←
FALSE]
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 => {};
};