<> <> <> <> <> <<>> <> <<>> 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 <> PolygonDescriptor: TYPE ~ CGReducer.Ref; <> 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: CARD _ LAST[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.ROPE _ NIL, undefSymb: LIST OF CARD _ NIL, included, fullyDefined, instantiated: BOOLEAN _ FALSE ]; <> 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: BOOLEAN _ FALSE; --debugging printout <> PolyCreate: PROC RETURNS [polygon: PolygonDescriptor] ~ { <> 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] = <> {CGReducer.Vertex[self: polygon, v: [x: x, y: y]]}; PolyGenerate: PROC[polygon: PolygonDescriptor, outputTrapezoid: PROC[llx, lrx, ly, ulx, urx, uy: REAL]] ~ { <> 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; }; <> 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]] }; <> 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]; }; <> DefDelete: PROC[i: CARD, data: REF ANY] ~ { KillBiggerThanI: PROC [key: IntHashTable.Key, value: IntHashTable.Value] RETURNS [quit: BOOLEAN _ FALSE] ~ { <> 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; <> 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] ~ { <> 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 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]]; 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 => {}; }; <<>> END.