<> <> <> <<>> DIRECTORY Basics, CD, CDBasics, CDDirectory, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Core, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DP, RefTab, IO, PW, PWCore, Rope, Sisyph, TerminalIO; DPLayout: CEDAR PROGRAM IMPORTS Basics, CD, CDBasics, CDDirectory, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DP, RefTab, IO, PW, PWCore, Rope, Sisyph, TerminalIO EXPORTS DP SHARES CDRects = BEGIN Signal: SIGNAL[msg: DP.ROPE _ NIL] = CODE; DrawingError: SIGNAL = CODE; schDeco: PUBLIC CoreGeometry.Decoration _ Sisyph.mode.decoration; layDeco: PUBLIC CoreGeometry.Decoration _ PWCore.extractMode.decoration; layRules: ATOM _ $cmosB; Layout: PWCore.LayoutProc ~ { data: CoreClasses.RecordCellType _ NARROW[cellType.data]; spec: DP.DPSpec _ NARROW[CoreProperties.GetProp[cellType.properties, $DPSpec].value]; schIR: CD.Rect _ [x1: LAST[INT], x2: FIRST[INT], y1: LAST[INT], y2: FIRST[INT]]; xIntervals: DP.Intervals _ NIL; yIntervals: DP.Intervals _ NIL; yIntervalsSB: DP.Intervals _ NIL; colChans: NAT _ spec.chans*DP.schChanW; count: NAT _ 0; nofRows: NAT _ 0; nofCols: NAT _ 0; row: NAT _ 0; col: NAT _ 0; transistors: INT _ 0; dp: DP.DataPath _ NIL; loc: CD.Position; size: CD.Position; <> <> FOR child: NAT IN [0..data.size) DO count: INT _ CountTransistors[data.instances[child].type]; IF count=0 THEN {TerminalIO.PutF["Warning: Zero transistor celltype: %g\n", IO.rope[CoreOps.GetCellTypeName[data.instances[child].type]]]}; transistors _ transistors + count; [loc, size] _ LocSize[data.instances[child]]; IF size.x=(spec.dChans*DP.schChanW) THEN xIntervals _ InsertInterval[[loc.x-colChans, size.x+colChans], xIntervals] ELSE xIntervals _ InsertInterval[[loc.x, size.x], xIntervals]; yIntervals _ InsertInterval[[loc.y, size.y], yIntervals]; ENDLOOP; <> yIntervalsSB _ FindSBIntervals[cellType, yIntervals]; <> FOR list: DP.Intervals _ yIntervals, list.rest WHILE list#NIL DO nofRows _ nofRows+1; schIR.y1 _ MIN[schIR.y1, list.first.loc]; schIR.y2 _ MAX[schIR.y2, list.first.loc + list.first.size]; IF list.rest#NIL AND list.first.loc + list.first.size > list.rest.first.loc THEN Signal[ IO.PutFR["Rows %g and %g Overlap\n", IO.int[nofRows], IO.int[nofRows+1]]] ENDLOOP; FOR list: DP.Intervals _ yIntervalsSB, list.rest WHILE list#NIL DO nofRows _ nofRows+1; schIR.y1 _ MIN[schIR.y1, list.first.loc]; schIR.y2 _ MAX[schIR.y2, list.first.loc + list.first.size]; IF list.rest#NIL AND list.first.loc + list.first.size > list.rest.first.loc THEN Signal[] ENDLOOP; FOR list: DP.Intervals _ xIntervals, list.rest WHILE list#NIL DO nofCols _ nofCols+1; schIR.x1 _ MIN[schIR.x1, list.first.loc]; schIR.x2 _ MAX[schIR.x2, list.first.loc + list.first.size]; IF list.rest#NIL AND list.first.loc + list.first.size > list.rest.first.loc THEN Signal[] ENDLOOP; <> dp _ NEW[DP.RowSeqRec[nofRows]]; dp.schIR _ schIR; dp.cell _ cellType; dp.spec _ spec; dp.wpo _ RefTab.Create[]; IF dp.spec.cols#0 AND dp.spec.cols#nofCols THEN Signal[]; dp.spec.cols _ nofCols; IF dp.spec.xforms = NIL THEN dp.spec.xforms _ LIST[[dp.spec.cols, 0], [dp.spec.n, 1]]; FOR row IN [0..dp.size) DO sb: BOOL _ yIntervals=NIL OR yIntervalsSB#NIL AND yIntervalsSB.first.loc> AddSchematicGeometrySB[dp]; FOR row IN [0..dp.size) DO IF dp[row].sb#NIL THEN DP.BuildSB[dp, row] ENDLOOP; <> FOR child: NAT IN [0..data.size) DO <> [loc, size] _ LocSize[data.instances[child]]; FOR row DECREASING IN [0..dp.size) DO IF dp[row].schIR.y1 <= loc.y THEN EXIT REPEAT FINISHED => Signal[] ENDLOOP; FOR col DECREASING IN [0..dp[row].size) DO IF dp[row][col].schIR.x1 <= loc.x THEN EXIT REPEAT FINISHED => Signal[] ENDLOOP; IF dp[row][col].schInst#NIL THEN Signal[]; dp[row][col].schInst _ data.instances[child]; dp[row][col].devCells _ GetDeviceCellTypes[dp, data.instances[child]]; IF (SchHalfChan[loc.x - dp[row][col].schIR.x1] MOD 2) # 0 THEN Signal[]; dp[row][col].devCOff _ SchHalfChan[loc.x - dp[row][col].schIR.x1]/2; dp[row].layY.size _ CDBasics.SizeOfRect[PWCore.InterestRect[dp[row][col].devCells[0]]].y ENDLOOP; InitRouting[dp]; <> FOR row IN [1..dp.size) DO dp[row].layY.loc _ dp[row-1].layY.loc+dp[row-1].layY.size ENDLOOP; dp.layIR _ [ x1: 0, x2: BitWidth[dp]*dp.spec.cols*dp.spec.n, y1: 0, y2: dp[dp.size-1].layY.loc+dp[dp.size-1].layY.size ]; <> AddSchematicGeometry[dp]; AddGlobalRoutingInformation[dp]; obj _ dp.obj _ AssembleObject[dp]; TerminalIO.PutF["\nLayout %g\n", IO.rope[CoreOps.GetCellTypeName[cellType]]]; TerminalIO.PutF[" %g transistors\n", IO.int[transistors]]; ShowDP[dp]; TerminalIO.PutF["Layout Size (lambda) x: %g y: %g xy: %g\n", IO.int[CD.InterestSize[obj].x/DP.lambda], IO.int[CD.InterestSize[obj].y/DP.lambda], IO.int[(CD.InterestSize[obj].x/DP.lambda)*(CD.InterestSize[obj].y/DP.lambda)] ]}; InitRouting: PROC[dp: DP.DataPath] = { gnd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Gnd"]; vdd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Vdd"]; FOR row: INT DECREASING IN [0..dp.size) DO ytop: INT _ dp[row].layY.size; FOR col: INT DECREASING IN [0..dp[row].size) DO dp[row][col].wpo _ RefTab.Create[]; IF dp[row].sb#NIL THEN LOOP; IF dp[row][col].schInst=NIL THEN { AddPObj[dp[row][col].wpo, gnd, VerPObj[0, ytop, (dp.spec.chans+1)*2-1, DP.pwrW]]; AddPObj[dp[row][col].wpo, vdd, VerPObj[0, ytop, (dp.spec.chans+2)*2-1, DP.pwrW]]}; ENDLOOP ENDLOOP}; BitWidth: PUBLIC PROC[dp: DP.DataPath] RETURNS[bitWidth: INT] = {RETURN[(dp.spec.chans+ dp.spec.dChans)*DP.layChanW]}; EachWireInst: TYPE = PROC[w: DP.Wire, geo: CoreGeometry.Instance]; EnumInternalSchematicGeometry: PROC[cell: DP.CellType, eachWireInst: EachWireInst] = { data: CoreClasses.RecordCellType _ NARROW[cell.data]; EnumSchematicGeometry: CoreOps.EachWireProc ~ { geometry: CoreGeometry.Instances _ CoreGeometry.GetGeometry[schDeco, wire]; IF geometry=NIL THEN RETURN[subWires: TRUE]; FOR geometry _ geometry, geometry.rest WHILE geometry#NIL DO eachWireInst[wire, geometry.first] ENDLOOP; RETURN[subWires: TRUE]}; []_CoreOps.VisitWire[data.internal, EnumSchematicGeometry]}; FindSBIntervals: PROC[cell: DP.CellType, instY: DP.Intervals] RETURNS[sbIVals: DP.Intervals_NIL] = { data: CoreClasses.RecordCellType _ NARROW[cell.data]; CheckAndAdd: PROC[loc: INT] = { last: INT _ schIR.y1+2; FOR list: DP.Intervals _ instY, list.rest WHILE list#NIL DO IF loc < list.first.loc THEN {sbIVals _ InsertInterval[[last, list.first.loc-last], sbIVals]; RETURN}; IF loc < list.first.loc + list.first.size THEN RETURN; last _ list.first.loc + list.first.size; REPEAT FINISHED => sbIVals _ InsertInterval[[last, schIR.y2-2-last], sbIVals] ENDLOOP}; eachWireInst: EachWireInst = { instIR: CD.Rect _ CDBasics.MapRect[CD.InterestRect[geo.obj], geo.trans]; hor: BOOL _ (instIR.x2-instIR.x1) >= DP.schChanW/2; loc: INT _ (instIR.y1+instIR.y2)/2; IF hor THEN CheckAndAdd[loc]}; schIR: CD.Rect _ CD.InterestRect[CoreGeometry.GetObject[schDeco, cell]]; FOR child: NAT IN [0..data.size) DO pos, size: CD.Position; <> [pos, size] _ LocSize[data.instances[child]]; CheckAndAdd[pos.y + size.y/2]; ENDLOOP; EnumInternalSchematicGeometry[cell, eachWireInst]}; AddSchematicGeometrySB: PROC[dp: DP.DataPath] = { eachWireInst: EachWireInst = { instIR: CD.Rect _ CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans]; lc: DP.LayoutCoord _ GetLayoutCoord[dp, w, instIR, TRUE]; IF lc.hor OR lc.inBody THEN FOR row: NAT IN [lc.rowBot..lc.rowTop] DO IF dp[row].sb#NIL THEN DP.AddSBNode[dp, row, w, lc]; ENDLOOP}; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; AddSchematicGeometry: PROC[dp: DP.DataPath] = { eachWireInst: EachWireInst = { instIR: CD.Rect _ CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans]; bigLC: DP.LayoutCoord _ GetLayoutCoord[dp, w, instIR, FALSE]; IF geo.obj.class#CDRects.bareRectClass THEN Signal[]; <> IF bigLC.inBody THEN FOR row: NAT IN [bigLC.rowBot..bigLC.rowTop] DO IF dp[row].sb#NIL THEN LOOP; FOR col: NAT IN [bigLC.colLt..bigLC.colRt] DO lc: DP.LayoutCoord _ TrimLayoutCoord[dp, bigLC, row, col]; IF lc.hor THEN { IF lc.chanLt IN [1..dp.spec.chans*2) THEN AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanLt, lc.yTop, lc.horLayTop]]; IF lc.chanRt IN [1..dp.spec.chans*2) THEN AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanRt, lc.yTop, lc.horLayTop]]; AddPObj[dp[row][col].wpo, w, HorPObj[lc.yTop, lc.chanLt, lc.chanRt, lc.horSize, lc.horLayTop]]}; IF ~lc.hor THEN { IF lc.yBot IN (0..dp[row].layY.size) THEN AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanLt, lc.yBot, lc.horLayBot]]; IF lc.yTop IN (0..dp[row].layY.size) THEN AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanLt, lc.yTop, lc.horLayTop]]; AddPObj[dp[row][col].wpo, w, VerPObj[lc.yBot, lc.yTop, lc.chanLt]]}; ENDLOOP; ENDLOOP; <> IF bigLC.sides#CoreGeometry.noSide THEN { tag: DP.Object _ IF bigLC.hor THEN tagHor ELSE tagVer; FOR side: DP.Side IN DP.Side DO loc: CD.Position; IF NOT bigLC.sides[side] THEN LOOP; IF side=top OR side=bottom THEN FOR bit: INT IN [0..dp.spec.n) DO kid: DP.Wire _ IF w.size=0 THEN w ELSE w[bit]; xform: CoreXform.Xform _ CoreXform.GenXform[dp.spec.xforms]; logical: INT _ bigLC.colLt*dp.spec.n + bit; loc.y _ SELECT side FROM bottom => 0, top => dp.layIR.y2 - CD.InterestSize[tag].y ENDCASE=>ERROR; loc.x _ BitWidth[dp] * CoreXform.XformIndex[xform, lr, logical].i + DP.leftTail + (bigLC.chanLt-1)*DP.layChanW/2 - DP.metW/2; AddPObj[dp.wpo, kid, [tag, loc]]; AddPin[ kid, [tag, loc]]; ENDLOOP; IF side=left OR side=right THEN { range: INT _ IF w.size=0 THEN 1 ELSE w.size; FOR bit: INT IN [0..range) DO kid: DP.Wire _ IF w.size=0 THEN w ELSE w[bit]; layy: INT _ IF dp[bigLC.rowBot].sb#NIL THEN DP.GetSBY[dp[bigLC.rowBot].sb, kid].loc ELSE bigLC.yBot; IF dp[bigLC.rowBot].sb=NIL AND w.size#0 THEN ERROR; loc.x _ SELECT side FROM left => 0, right => dp.layIR.x2- CD.InterestSize[tag].x, ENDCASE =>ERROR; loc.y _ dp[bigLC.rowBot].layY.loc + layy - bigLC.horSize/2; AddPObj[dp.wpo, kid, [tag, loc]]; AddPin[ kid, [tag, loc]]; ENDLOOP}; ENDLOOP } }; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; <> <> <> <> <> <> <> <> <> <> <> <<[atEdge, collt, bitlt] _ NextLeftIndexes[dp, col, 1]; -- ???Bit????>> <> GetGlobalNames: PROC[dp: DP.DataPath] RETURNS[globals: LIST OF DP.ROPE] = {globals _ LIST["Gnd", "Vdd", "Vbb"]}; AddGlobalRoutingInformation: PROC[dp: DP.DataPath] = { FOR globals: LIST OF DP.ROPE _ GetGlobalNames[dp], globals.rest WHILE globals#NIL DO FOR row: NAT IN [0..dp.size) DO refCol: NAT; actualWire: DP.Wire; cell: DP.CellType; lss: LSs; IF dp[row].sb#NIL THEN LOOP; FOR refCol _ 0, refCol+1 WHILE refCol ERROR ENDLOOP; actualWire _ CoreOps.FindWire[dp[row][refCol].schInst.actual, globals.first]; cell _ dp[row][refCol].devCells[0]; lss _ GetGeometryLocSizes [cell, CoreOps.FindWire[cell.public, globals.first], right, CMosB.met2]; FOR lss _ lss, lss.rest WHILE lss#NIL DO FOR col: NAT IN [0..dp[row].size) DO cWidth: INT _ dp.spec.chans + (IF dp[row][refCol].schInst=NIL THEN dp.spec.dChans ELSE 0); AddPObj[ dp[row][col].wpo, actualWire, HorPObj[lss.first.loc+lss.first.size/2, 0, cWidth*2, lss.first.size, CMosB.met2] ]; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP; AddGlobalSideDecorations[dp]; AddGlobalEndDecorations[dp]}; tagVer: DP.Object _ CDRects.CreateRect[ [x: DP.metW, y: DP.pinSize], CMosB.met]; tagHor: DP.Object _ CDRects.CreateRect[ [x: DP.pinSize, y: DP.met2W], CMosB.met2]; AddGlobalSideDecorations: PROC[dp: DP.DataPath] = { loc: CD.Position; tag: DP.Object; FOR row: NAT IN [0..dp.size) DO FOR globals: LIST OF DP.ROPE _ GetGlobalNames[dp], globals.rest WHILE globals#NIL DO cell: DP.CellType; wire: DP.Wire; actWire: DP.Wire _ CoreOps.FindWire[dp.cell.public, globals.first]; lssLt, lssRt: LSs; IF dp[row].sb#NIL THEN { lss: LSRec; IF NOT RefTab.Fetch[dp[row].sb, actWire].found THEN LOOP; lss _ [loc: DP.GetSBY[dp[row].sb, actWire].loc - DP.met2W/2, size: DP.met2W]; lssLt _ CONS[lss, NIL]; lssRt _ CONS[lss, NIL]} ELSE { FOR refCol: INT _ 0, refCol+1 WHILE refCol ERROR ENDLOOP; FOR refCol: INT _ dp[row].size-1, refCol-1 WHILE refCol>=0 DO IF dp[row][refCol].schInst=NIL THEN LOOP; cell _ dp[row][refCol].devCells[0]; wire _ CoreOps.FindWire[cell.public, globals.first]; lssRt _ GetGeometryLocSizes[dp[row][refCol].devCells[0], wire, right, CMosB.met2]; EXIT REPEAT FINISHED => ERROR ENDLOOP}; FOR lss: LSs _ lssLt, lss.rest WHILE lss#NIL DO tag _ CDRects.CreateRect[ [x: DP.pinSize, y: lss.first.size], CMosB.met2]; loc _ [0, dp[row].layY.loc + lss.first.loc]; AddPObj[dp.wpo, actWire, [tag, loc]]; AddPin[ actWire, [tag, loc]] ENDLOOP; FOR lss: LSs _ lssRt, lss.rest WHILE lss#NIL DO tag _ CDRects.CreateRect[ [x: DP.pinSize, y: lss.first.size], CMosB.met2]; loc _ [dp.spec.cols*dp.spec.n*BitWidth[dp]- CD.InterestSize[tag].x, dp[row].layY.loc + lss.first.loc]; AddPObj[dp.wpo, actWire, [tag, loc]]; AddPin[ actWire, [tag, loc]] ENDLOOP; ENDLOOP; ENDLOOP}; pwrSep: INT _ 1; AddGlobalEndDecorations: PROC[dp: DP.DataPath] = { gnd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Gnd"]; vdd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Vdd"]; tag: CD.Object _ CDRects.CreateRect[ [x: DP.pwrW, y: DP.pinSize], CMosB.met]; FOR row: INT _ 0, row+dp.size-1 WHILE row< dp.size DO topPos: CD.Position _ [0, dp[row].layY.loc + dp[row].layY.size - CD.InterestSize[tag].y]; botPos: CD.Position _ [0, 0]; FOR col: INT IN [0..dp[row].size) DO FOR bit: NAT IN [0..dp.spec.n) DO gndx: INT _ BitWidth[dp]*(col*dp.spec.n+bit) + dp.spec.chans*DP.layChanW + DP.leftTail - CD.InterestSize[tag].x/2; vddx: INT _ gndx + pwrSep*DP.layChanW; IF row+1=dp.size THEN { topPos.x _ gndx; AddPObj[dp.wpo, gnd, [tag, topPos]]; AddPin[gnd, [tag, topPos]]; topPos.x _ vddx; AddPObj[dp.wpo, vdd, [tag, topPos]]; AddPin[vdd, [tag, topPos]]}; IF row=0 THEN { botPos.x _ gndx; AddPObj[dp.wpo, gnd, [tag, botPos]]; AddPin[gnd, [tag, botPos]]; botPos.x _ vddx; AddPObj[dp.wpo, vdd, [tag, botPos]]; AddPin[vdd, [tag, botPos]]}; ENDLOOP ENDLOOP ENDLOOP}; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> BitPosX: PUBLIC PROC[dp: DP.DataPath, col, bit: NAT] RETURNS[pos: INT] = { xform: CoreXform.Xform _ CoreXform.GenXform[dp.spec.xforms]; logical: INT _ col*dp.spec.n + bit; RETURN[BitWidth[dp] * CoreXform.XformIndex[xform, lr, logical].i ]}; slop: INT _ DP.schChanW/4; GetInBodyIR: PROC[dp: DP.DataPath, schIR: CD.Rect] RETURNS[BOOL] = { schBodyIR: CD.Rect _ [ x1: dp[0][0].schIR.x1, y1: dp[0][0].schIR.y1, x2: dp[dp.size-1][dp[0].size-1].schIR.x2, y2: dp[dp.size-1][dp[0].size-1].schIR.y2]; RETURN[CDBasics.Intersect[schIR, CDBasics.Extend[schBodyIR, -1]]]}; GetLayoutCoordSides: PROC[dp: DP.DataPath, schIR: CD.Rect] RETURNS[sides: DP.Sides] = { externalIR: CD.Rect _ CD.InterestRect[CoreGeometry.GetObject[schDeco, dp.cell]]; sides[left] _ schIR.x1 < externalIR.x1 + slop; sides[bottom] _ schIR.y1 < externalIR.y1 + slop; sides[right] _ schIR.x2 > externalIR.x2 - slop; sides[top] _ schIR.y2 > externalIR.y2 - slop}; <> <> GetLayoutHor: PROC[schIR: CD.Rect] RETURNS[hor: BOOL] = { comp: Basics.Comparison _ Basics.CompareInt[schIR.x2-schIR.x1, schIR.y2-schIR.y1]; RETURN[SELECT comp FROM less => FALSE, greater => TRUE, ENDCASE => TRUE]}; -- little wire icon pins GetLayoutCoord: PROC[dp: DP.DataPath, wire: DP.Wire, schIR: CD.Rect, initialLayYSize: BOOL] RETURNS[lc: DP.LayoutCoord] = { lc.inBody _ GetInBodyIR[dp, schIR]; lc.sides _ GetLayoutCoordSides[dp, schIR]; lc.hor _ GetLayoutHor[schIR]; FOR row: NAT IN [0..dp.size) DO FOR col: NAT IN [0..dp[row].size) DO OPEN CDB: CDBasics; ENABLE DrawingError => { TerminalIO.PutF["Drawing Error in row %g col %g\n", IO.int[row], IO.int[col]]; TerminalIO.PutF[" x1: %g y1: %g x2: %g y2: %g \n", IO.int[schIR.x1], IO.int[schIR.y1], IO.int[schIR.x2], IO.int[schIR.y2]]; REJECT}; GetY: PROC[schy: INT] RETURNS[layy, size: INT, layer: CD.Layer] = { <> layer _ CMosB.met2; IF initialLayYSize OR dp[row].sb#NIL THEN RETURN[DP.initialYSize/2, DP.met2W, CMosB.met2]; FOR sideIndex: INT IN [0..1] DO side: DP.Side _ IF (sideIndex=0)=firstSideRight THEN right ELSE left; incr: INT _ IF side=right THEN -1 ELSE +1; FOR cc: INT _ col, cc+incr WHILE cc IN [0..dp.spec.cols) DO IF dp[row][cc].schInst=NIL THEN LOOP; THROUGH [0..1] DO -- check both pol and met2 lss: LSs _ IconToLayoutGeoLocSizes[dp[row][cc], wire, schy, side, layer]; IF lss#NIL THEN RETURN[lss.first.loc+lss.first.size/2, lss.first.size, layer]; layer _ IF layer=CMosB.pol THEN CMosB.met2 ELSE CMosB.pol; ENDLOOP ENDLOOP ENDLOOP; ERROR}; firstSideRight: BOOL _ FALSE; slopGap: INT _ IF row>0 THEN dp[row].schIR.y1 - dp[row-1].schIR.y2 + slop ELSE slop; SELECT TRUE FROM CDB.Intersect[schIR, CDB.Extend[dp[row][col].schIR,-1]] => { }; -- doit lc.inBody => LOOP; lc.sides[bottom] AND row = 0 => { }; -- doit lc.sides[left] AND col = 0 => { }; -- doit lc.sides[top] AND row = dp.size-1 => { }; -- doit lc.sides[right] AND col = dp[0].size-1 => { }; -- doit ENDCASE => LOOP; IF lc.hor AND schIR.x1 <= dp[row][col].schIR.x1 OR lc.hor AND schIR.x2 >= dp[row][col].schIR.x2 THEN firstSideRight _ TRUE; IF schIR.x1 IN [dp[row][col].schIR.x1-slop..dp[row][col].schIR.x1+slop) THEN { lc.colLt _ col; lc.chanLt _ 0}; IF schIR.x1 IN [dp[row][col].schIR.x1+slop..dp[row][col].schIR.x2-slop) THEN { lc.colLt _ col; lc.chanLt _ SchHalfChan[schIR.x1-dp[row][col].schIR.x1]}; IF schIR.x2 IN (dp[row][col].schIR.x1+slop..dp[row][col].schIR.x2-slop) THEN { lc.colRt _ col; lc.chanRt _ SchHalfChan[schIR.x2-dp[row][col].schIR.x1]}; IF schIR.x2 >= dp[row][col].schIR.x2-slop THEN { lc.colRt _ col; lc.chanRt _ SchHalfChan[dp[row][col].schIR.x2-dp[row][col].schIR.x1]}; IF schIR.y1 IN [dp[row].schIR.y1-slopGap..dp[row].schIR.y1+slop] THEN { lc.rowBot _ row; lc.yBot _ 0}; IF schIR.y1 IN (dp[row].schIR.y1+slop..dp[row].schIR.y2-slop) THEN { lc.rowBot _ row; [lc.yBot, lc.horSize, lc.horLayBot] _ GetY[schIR.y1-dp[row].schIR.y1]}; IF schIR.y2 IN (dp[row].schIR.y1+slop..dp[row].schIR.y2-slop) THEN { lc.rowTop _ row; [lc.yTop, lc.horSize, lc.horLayTop] _ GetY[schIR.y2-dp[row].schIR.y1]}; IF schIR.y2 >= dp[row].schIR.y2-slop THEN { lc.rowTop _ row; lc.yTop _ IF initialLayYSize THEN DP.initialYSize ELSE dp[row].layY.size}; ENDLOOP; ENDLOOP}; TrimLayoutCoord: PROC[dp: DP.DataPath, bigLC: DP.LayoutCoord, row, col: NAT] RETURNS[lc: DP.LayoutCoord] = { lc _ bigLC; IF col > bigLC.colLt THEN lc.chanLt _ 0; IF col < bigLC.colRt THEN lc.chanRt _ (dp.spec.chans+ dp.spec.dChans)*2; IF row > bigLC.rowBot THEN lc.yBot _ 0; IF row < bigLC.rowTop THEN lc.yTop _ dp[row].layY.size; lc.rowTop _ lc.rowBot _ row; lc.colLt _ lc.colRt _ col }; AddPin: PROC [public: DP.Wire, po: DP.PObj] = { pin: CoreGeometry.Instance _ [po.object, [po.position]]; CoreGeometry.AddPins[layDeco, public, LIST[pin]]}; IconToLayoutGeoLocSizes: PROC [sec: DP.Section, actual: DP.Wire, schLoc: INT, side: DP.Side, layer: CD.Layer] RETURNS[lss: LSs] = { iconPub: DP.Wire _ GetSchematicPublic[sec.schInst, actual, side, schLoc]; bitCellPub: DP.Wire; bitCell: DP.CellType _ sec.devCells[0]; name: DP.ROPE; IF iconPub=NIL THEN DrawingError[]; name _ CoreOps.GetShortWireName[iconPub]; IF name=NIL THEN name _ DP.GetCharCode[iconPub]; bitCellPub _ CoreCreate.FindWire[bitCell.public, name]; IF bitCellPub=NIL THEN Signal[]; RETURN [GetGeometryLocSizes[bitCell, bitCellPub, side, layer]]}; GetSchematicPublic: PROC [cellInst: DP.CellInstance, actual: DP.Wire, cSide: DP.Side, schY: INT] RETURNS[schPub: DP.Wire _ NIL] = { eachPair: CoreOps.EachWirePairProc ~ { lss: LSs; IF (actual # actualWire) THEN RETURN; lss _ GetGeometryLocSizes[cellInst.type, publicWire, cSide]; FOR lss _ lss, lss.rest WHILE lss#NIL DO IF schY-lss.first.loc IN [0..lss.first.size] THEN EXIT; REPEAT FINISHED=>RETURN[subWires: FALSE]; ENDLOOP; schPub _ publicWire; RETURN[quit: TRUE]}; []_CoreOps.VisitBinding[cellInst.actual, cellInst.type.public, eachPair]}; LSs: TYPE = LIST OF LSRec; LSRec: TYPE = RECORD[loc, size: INT]; GetGeometryLocSizes: PROC [cell: DP.CellType, wire: DP.Wire, cSide: DP.Side, lay: CD.Layer _ CD.commentLayer] RETURNS[lss: LSs _ NIL] = { eachPin: CoreGeometry.EachPinProc = { IF (layer # lay) OR (side # cSide) THEN RETURN; lss _ CONS[LSRec[min, max-min], lss]}; decoration: CoreGeometry.Decoration _ IF lay=CD.commentLayer THEN schDeco ELSE layDeco; IF wire=NIL THEN RETURN[NIL]; []_CoreGeometry.EnumerateSides[decoration, cell, wire, eachPin]}; SchHalfChan: PUBLIC PROC[pos: INT] RETURNS[chan: INT] = { RETURN[pos/(DP.schChanW/2)]}; ContPObj: PROC[chan, layY: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = { po.object _ CDSimpleRules.Contact[layRules, CMosB.met, layer]; po.position.x _ DP.leftTail + (chan-1)*DP.layChanW/2 - DP.cnctSize/2; po.position.y _ layY - DP.cnctSize/2}; HorPObj: PROC[layY, lChan, rChan, size: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = { offSet: INT _ DP.leftTail-DP.layChanW/2; ltEdge: BOOL _ lChan = 0; rtEdge: BOOL _ rChan MOD 2 = 0; x1: INT _ DP.leftTail + (lChan-1) * DP.layChanW/2 - (IF ltEdge THEN offSet ELSE 0); x2: INT _ DP.leftTail + (rChan-1) * DP.layChanW/2 - (IF rtEdge THEN offSet ELSE 0); IF x1 >= x2 THEN Signal[]; po.object _ CDRects.CreateRect[ [x: x2-x1, y: size], layer]; po.position _ [x1, layY - size/2]}; VerPObj: PROC[layYbot, layYtop, chan: INT, size: INT _ DP.metW] RETURNS[po: DP.PObj] = { IF layYbot >= layYtop THEN Signal[]; po.object _ CDRects.CreateRect[ [x: size, y: layYtop-layYbot], CMosB.met]; po.position.x _ DP.leftTail + (chan-1)*DP.layChanW/2 - size/2; po.position.y _ layYbot}; AddPObj: PROC[wpo: RefTab.Ref, wire: DP.Wire, po: DP.PObj] = { pos: DP.PObjs _ NARROW[RefTab.Fetch[wpo, wire].val]; pos _ CONS[po, pos]; [] _ RefTab.Store[wpo, wire, pos]}; AssembleObject: PROC[dp: DP.DataPath] RETURNS[cell: DP.Object] = { IncludePins: RefTab.EachPairAction = { pos: DP.PObjs _ NARROW[val]; name: DP.ROPE _ CoreRoute.LabelInternal[data.internal, NARROW[key]]; FOR pos _ pos, pos.rest WHILE pos#NIL DO Include[pos.first.object, pos.first.position]; CDProperties.PutProp[insts.first, $SignalName, name] ENDLOOP}; Include: PROC[obj: CD.Object, loc: CD.Position] = { loc _ CDBasics.SubPoints[loc, CD.InterestBase[obj]]; -- for sb and mux offsets insts _ CONS[ NEW[CD.InstanceRep _ [obj, [loc]]], insts]}; data: CoreClasses.RecordCellType _ NARROW[dp.cell.data]; name: DP.ROPE _ CoreOps.GetCellTypeName[dp.cell]; insts: CD.InstanceList _ NIL; xform: CoreXform.Xform _ CoreXform.GenXform[dp.spec.xforms]; FOR row: NAT IN [0..dp.size) DO IF dp[row].sb#NIL THEN { Include[dp[row].obj, [0, dp[row].layY.loc]]; LOOP}; FOR col: NAT IN [0..dp[row].size) DO routing: DP.Object _ CreateRoutingObject[dp, row, col, 0]; FOR bit: NAT IN [0..dp.spec.n) DO refPos: CD.Position _ [BitPosX[dp, col, bit] + 0, dp[row].layY.loc]; IF routing#NIL THEN Include[ obj: routing, loc: refPos ]; IF dp[row][col].schInst=NIL THEN LOOP; IF IsMux[dp[row][col].schInst.type] THEN { obj: CD.Object _ PWCore.Layout[dp[row][col].devCells[bit]]; new: CD.Object _ CDDirectory.Expand1[obj].new; IF new=NIL THEN ERROR; Include[obj: new, loc: [x: refPos.x, y: refPos.y ]]} ELSE Include[ obj: PWCore.Layout[dp[row][col].devCells[bit]], loc: [x: refPos.x+ dp[row][col].devCOff*DP.layChanW, y: refPos.y]]; ENDLOOP; ENDLOOP; ENDLOOP; [ ] _ RefTab.Pairs[dp.wpo, IncludePins]; cell _ PW.CreateCell[instances: insts, name: name.Cat[".mask"], ir: dp.layIR]}; <> <> <> <> <> <> <<-- min _ CDBasics.MinPoint[min, pos.first.position];>> <> <<[max, CDBasics.AddPoints[pos.first.position, CD.InterestSize[pos.first.object]]];>> <> <<[pos.first.object, [pos.first.position]]], insts] ENDLOOP};>> <> <> <<[ ] _ RefTab.Pairs[dp[row][col].wpo, action];>> <> <> <<>> CreateRoutingObject: PROC[dp: DP.DataPath, row, col, bit: INT] RETURNS[obj: DP.Object] = { data: CoreClasses.RecordCellType _ NARROW[dp.cell.data]; nodes: LIST OF CDRoutingObjects.Node; action: RefTab.EachPairAction = { name: IO.ROPE _ CoreRoute.LabelInternal[data.internal, NARROW[key]]; node: CDRoutingObjects.Node; pos: DP.PObjs _ GetPObjs[val, bit]; node _ CDRoutingObjects.CreateNode[pos, LIST [[key: $SignalName, val: name]]]; nodes _ CONS[node, nodes]}; IF RefTab.GetSize[dp[row][col].wpo]=0 THEN RETURN[NIL]; [ ] _ RefTab.Pairs[dp[row][col].wpo, action]; obj _ CDRoutingObjects.CreateRoutingObject[nodes, [0, 0, (dp.spec.chans)*DP.layChanW, dp[row].layY.size]]}; GetPObjs: PROC[value: REF, bit: INT] RETURNS[pos: DP.PObjs] = { WITH value SELECT FROM lopobjs: DP.PObjs => RETURN[lopobjs]; < RETURN[pobjseq[bit]];>> ENDCASE => ERROR}; GetDeviceCellTypes: PROC[dp: DP.DataPath, inst: DP.CellInstance] RETURNS[cells: DP.CellTypeSeq] = { IF IsMux[inst.type] THEN RETURN[DP.GetMuxCellTypes[dp, inst]]; cells _ NEW[DP.CellTypeSeqRec[dp.spec.n]]; FOR i: NAT IN [0..cells.size) DO cells[i] _ GetChild[inst.type, i] ENDLOOP}; IsMux: PROC[cell: DP.CellType] RETURNS[isMux: BOOL] = { rec: CoreClasses.RecordCellType; name: DP.ROPE _ CoreOps.GetCellTypeName[cell]; IF NOT ISTYPE[cell.data, CoreClasses.RecordCellType] THEN RETURN[FALSE]; IF name.Substr[MAX[0, name.Length-3], 3].Equal["Mux", FALSE] THEN RETURN[TRUE]; rec _ NARROW[cell.data]; RETURN[CoreOps.GetCellTypeName[rec[0].type].Equal["DP.DPMuxSwitch.icon"]]}; GetChild: PROC[cell: DP.CellType, bit: INT _ -1] RETURNS[child: DP.CellType] = { IF bit<0 THEN RETURN[cell]; -- -1 means no bitwise replication hierarchy WITH cell.data SELECT FROM seq: CoreClasses.SequenceCellType => RETURN[seq.base]; rec: CoreClasses.RecordCellType => RETURN[rec[bit].type]; ENDCASE => RETURN[GetChild[ CoreOps.Recast[cell], bit]]}; LocSize: PROC[inst: DP.CellInstance] RETURNS[loc, size: CD.Position] = { obj: CD.Object _ CoreGeometry.GetObject[schDeco, inst.type]; trans: CoreGeometry.Transformation _ CoreGeometry.GetTrans[schDeco, inst]; size _ CD.InterestSize[obj]; loc _ CDBasics.BaseOfRect[CDBasics.MapRect[CD.InterestRect[obj], trans]]; IF trans.orient # original THEN { Signal[IO.PutFR["Schematic object (%g) has been rotated or flipped\n", IO.rope[CoreOps.GetCellTypeName[inst.type] ] ] ] }}; InsertInterval: PROC[intvl: DP.Interval, intvls: DP.Intervals] RETURNS[result: DP.Intervals] = { result _ CONS[intvl, intvls]; FOR intvls _ result, intvls.rest WHILE intvls#NIL DO TwoIntervals: TYPE = RECORD[i0, i1: DP.Interval]; IF intvls.rest=NIL OR intvls.first.loc < intvls.rest.first.loc THEN RETURN; IF intvls.first = intvls.rest.first THEN {intvls.rest _ intvls.rest.rest; RETURN}; IF intvls.first.loc = intvls.rest.first.loc THEN IF intvls.first.size < intvls.rest.first.size THEN RETURN ELSE [intvls.first, intvls.rest.first] _ TwoIntervals[intvls.rest.first, intvls.first]; [intvls.first, intvls.rest.first] _ TwoIntervals[intvls.rest.first, intvls.first]; ENDLOOP}; ShowDP: PUBLIC PROC[dp: DP.DataPath] = { TerminalIO.PutF["Data Path Rows: %g\n", IO.rope[CoreOps.GetCellTypeName[dp.cell]]]; FOR row: NAT DECREASING IN [0..dp.size) DO mux: BOOL _ FALSE; name: DP.ROPE _ NIL; TerminalIO.PutF["%3g x1:%5g x2:%5g y1:%5g y2:%5g", IO.int[row], IO.int[dp[row].schIR.x1], IO.int[dp[row].schIR.x2], IO.int[dp[row].schIR.y1], IO.int[dp[row].schIR.y2] ]; FOR col: INT IN [0..dp.spec.cols) DO IF dp[row][col].schInst=NIL THEN LOOP; mux _ IsMux[dp[row][col].schInst.type]; name _ CoreOps.GetCellTypeName[dp[row][col].schInst.type]; EXIT ENDLOOP; SELECT TRUE FROM dp[row].sb # NIL => TerminalIO.PutF[" \tSB\t\t"]; mux => TerminalIO.PutF[" \tMux\t"]; ENDCASE => TerminalIO.PutF[" \t\t\t"]; TerminalIO.PutF["%g\n", IO.rope[name]]; ENDLOOP}; CountTransistors: PUBLIC PROC[cell: DP.CellType] RETURNS[count: INT _ 0] = { IF cell=NIL THEN RETURN[0]; SELECT cell.class FROM CoreClasses.transistorCellClass => RETURN[1]; CoreClasses.sequenceCellClass => { data: CoreClasses.SequenceCellType _ NARROW[cell.data]; count _ data.count*CountTransistors[data.base]}; CoreClasses.recordCellClass => { data: CoreClasses.RecordCellType _ NARROW[cell.data]; FOR child: NAT IN [0..data.size) DO count _ count + CountTransistors[ data.instances[child].type ] ENDLOOP }; ENDCASE => count _ CountTransistors[CoreOps.Recast[cell]] }; Decorate: PWCore.DecorateProc ~ { }; <> [] _ PWCore.RegisterLayoutAtom[$DP, Layout, Decorate]; END.