<> <> <> <> <<>> DIRECTORY Basics, CD, CDBasics, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Convert, Core, CoreClasses, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DataPath, RefTab, IO, PW, PWCore, Rope, Sisyph, SymTab, TerminalIO; DataPathLayout: CEDAR PROGRAM IMPORTS Basics, CD, CDBasics, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Convert, CoreClasses, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DataPath, RefTab, IO, PW, PWCore, Rope, Sisyph, SymTab, TerminalIO EXPORTS DataPath SHARES CDRects = BEGIN OPEN DP: DataPath; <> 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; dpKeyTab: SymTab.Ref _ SymTab.Create[]; sectionRtEdge: NAT _ LAST[NAT]; <> Layout: PWCore.LayoutProc ~ { data: CoreClasses.RecordCellType _ NARROW[cellType.data]; spec: DP.DPSpec _ NewCellTypeSpec[cellType]; interleave: BOOL _ CoreProperties.GetCellTypeProp[cellType, $DataPathInterleave]#NIL; refPolyBits: REF INT _ NARROW [CoreProperties.GetCellTypeProp[cellType, $ChanPolyBits]]; schIR: CD.Rect _ [x1: LAST[INT], x2: FIRST[INT], y1: LAST[INT], y2: FIRST[INT]]; xIntervals: DP.Intervals _ NIL; yIntervals: DP.Intervals _ NIL; yIntervalsCh: DP.Intervals _ NIL; colBuss: NAT _ spec.buses*spec.schBusW; count: NAT _ 0; nofRows: NAT _ 0; nofCols: NAT _ 0; row: NAT _ 0; col: NAT _ 0; dp: DP.Form _ NIL; loc: CD.Position; size: CD.Position; spec.n _ GetSize[data[0].type]; spec.cols _ 0; spec.interleave _ interleave; spec.chPolyBits _ IF refPolyBits#NIL THEN refPolyBits^ ELSE 0; <> <> FOR child: NAT IN [0..data.size) DO width: INT _ spec.schDWidth+colBuss; exposedBusses: INT; [loc, size] _ LocSize[data.instances[child]]; exposedBusses _ (width-size.x+slop)/spec.schBusW; -- icons must be correct width xIntervals _ InsertInterval[[loc.x-exposedBusses*spec.schBusW, width], xIntervals]; yIntervals _ InsertInterval[[loc.y, size.y], yIntervals]; ENDLOOP; yIntervalsCh _ FindChIntervals[spec, 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 _ yIntervalsCh, 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; FOR row IN [0..dp.size) DO sb: BOOL _ yIntervals=NIL OR yIntervalsCh#NIL AND yIntervalsCh.first.loc> 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]; IF (SchHalfBus[spec, loc.x - dp[row][col].schIR.x1] MOD 2) # 0 THEN Signal[]; dp[row][col].devBOff _ SchHalfBus[spec, loc.x - dp[row][col].schIR.x1]/2; ENDLOOP; ShowDP[dp]; <> FOR row IN [0..dp.size) DO IF dp[row].ch=NIL THEN FOR col IN [0..dp[row].size) DO IF dp[row][col].schInst=NIL THEN LOOP; dp[row][col].devCells _ GetDeviceCellTypes[dp[row][col].schInst]; dp[row].layY.size _ CDBasics.SizeOfRect[PWCore.InterestRect[dp[row][col].devCells[0]]].y ENDLOOP ENDLOOP; <> AddExplicitRoutingChannel[dp]; AddImplicitRoutingChannel[dp]; FOR row IN [0..dp.size) DO IF dp[row].ch#NIL THEN DP.BuildChan[dp, row] ENDLOOP; <> 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.spec]*dp.spec.cols*dp.spec.n, y1: 0, y2: dp[dp.size-1].layY.loc+dp[dp.size-1].layY.size ]; <> AddExplicitRoutingSwitchBox[dp]; AddImplicitRoutingSwitchBox[dp]; AddExplicitDecorations[dp]; AddImplicitDecorations[dp]; obj _ dp.obj _ AssembleObject[dp]; TerminalIO.PutF["\nLayout %g\n", IO.rope[CoreOps.GetCellTypeName[dp.cell]]]; TerminalIO.PutF[" %g transistors\n", IO.int[CountTransistors[dp.cell]]]; ShowDP[dp]; TerminalIO.PutF["Layout Size (CMosB.lambda) x: %g y: %g xy: %g\n", IO.int[CD.InterestSize[obj].x/CMosB.lambda], IO.int[CD.InterestSize[obj].y/CMosB.lambda], IO.int[(CD.InterestSize[obj].x/CMosB.lambda)*(CD.InterestSize[obj].y/CMosB.lambda)] ]}; <> FindChIntervals: PROC[spec: DP.DPSpec, 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) >= spec.schBusW/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]}; 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}; <> EachWireInst: TYPE = PROC[w: DP.Wire, geo: CoreGeometry.Instance]; GetGlobalNames: PROC[dp: DP.Form] RETURNS[globals: LIST OF DP.ROPE] = {globals _ LIST["Gnd", "Vdd", "Vbb"]}; EnumInternalSchematicGeometry: PROC[cell: DP.CellType, eachWireInst: EachWireInst] = { data: CoreClasses.RecordCellType _ NARROW[cell.data]; EnumSchematicGeometry: CoreOps.EachWireProc ~ { geometry: CoreGeometry.Instances _ CoreGeometry.GetGeometry[schDeco, wire]; IF ~RefTab.Store[visitOnceTab, wire, wire] THEN RETURN[FALSE, FALSE]; -- only once IF geometry=NIL THEN RETURN[subWires: TRUE]; FOR geometry _ geometry, geometry.rest WHILE geometry#NIL DO eachWireInst[wire, geometry.first] ENDLOOP; RETURN[subWires: TRUE]}; visitOnceTab: RefTab.Ref _ RefTab.Create[]; []_CoreOps.VisitWire[data.internal, EnumSchematicGeometry]; RefTab.Erase[visitOnceTab]; visitOnceTab _ NIL}; AddExplicitRoutingChannel: PROC[dp: DP.Form] = { 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].ch#NIL THEN DP.AddChanNode[dp, row, w, lc]; ENDLOOP}; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; AddImplicitRoutingChannel: PROC[dp: DP.Form] = { FOR row: INT DECREASING IN [0..dp.size) DO IF dp[row].ch#NIL THEN DP.AddPowerPassBuses[dp, row] ENDLOOP}; AddExplicitRoutingSwitchBox: PROC[dp: DP.Form] = { 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].ch#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.busLt IN [1..dp.spec.buses*2) THEN AddPObj[dp[row][col].wpo, w, ContPObj[dp.spec, lc.busLt, lc.yTop, lc.horLayTop]]; IF lc.busRt IN [1..dp.spec.buses*2) THEN AddPObj[dp[row][col].wpo, w, ContPObj[dp.spec, lc.busRt, lc.yTop, lc.horLayTop]]; AddPObj[dp[row][col].wpo, w, HorPObj[dp.spec, lc.yTop, lc.busLt, lc.busRt, 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[dp.spec, lc.busLt, lc.yBot, lc.horLayBot]]; IF lc.yTop IN (0..dp[row].layY.size) THEN AddPObj[dp[row][col].wpo, w, ContPObj[dp.spec, lc.busLt, lc.yTop, lc.horLayTop]]; AddPObj[dp[row][col].wpo, w, VerPObj[dp.spec, lc.yBot, lc.yTop, lc.busLt, dp.spec.metW]]}; ENDLOOP; ENDLOOP}; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; AddImplicitRoutingSwitchBox: PROC[dp: DP.Form] = { AddImplicitRoutingSwitchBoxSides[dp]; AddImplicitRoutingSwitchBoxEnds[dp]}; -- only needed for missing instances AddImplicitRoutingSwitchBoxSides: PROC[dp: DP.Form] = { 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].ch#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 _ IF dp[row][col].schInst=NIL THEN sectionRtEdge ELSE dp[row][col].devBOff*2; IF cWidth > 0 THEN AddPObj[ dp[row][col].wpo, actualWire, HorPObj[dp.spec, lss.first.loc+lss.first.size/2,0,cWidth,lss.first.size,CMosB.met2] ]; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP}; AddImplicitRoutingSwitchBoxEnds: PROC[dp: DP.Form] = { gnd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Gnd"]; vdd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Vdd"]; IF dp.spec.gndBus<=0 THEN RETURN; IF dp.spec.vddBus<=0 THEN ERROR; FOR row: INT DECREASING IN [0..dp.size) DO ytop: INT _ dp[row].layY.size; IF dp[row].ch#NIL THEN LOOP; FOR col: INT DECREASING IN [0..dp[row].size) DO IF dp[row][col].schInst#NIL THEN LOOP; AddPObj[dp[row][col].wpo, gnd, VerPObj[dp.spec, 0, ytop, (dp.spec.gndBus+1)*2-1, dp.spec.pwrW]]; AddPObj[dp[row][col].wpo, vdd, VerPObj[dp.spec, 0, ytop, (dp.spec.vddBus+1)*2-1, dp.spec.pwrW]]; ENDLOOP ENDLOOP}; AddExplicitDecorations: PROC[dp: DP.Form] = { tagVer: DP.Object _ CDRects.CreateRect[ [x: dp.spec.metW, y: dp.spec.pinSize], CMosB.met]; tagHor: DP.Object _ CDRects.CreateRect[ [x: dp.spec.pinSize, y: dp.spec.met2W], CMosB.met2]; eachWireInst: EachWireInst = { instIR: CD.Rect _ CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans]; bigLC: DP.LayoutCoord _ GetLayoutCoord[dp, w, instIR, FALSE]; 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]; loc.y _ SELECT side FROM bottom => 0, top => dp.layIR.y2 - CD.InterestSize[tag].y ENDCASE=>ERROR; loc.x _ BitPosX[dp.spec, bigLC.colLt, bit] + dp.spec.leftTail + (bigLC.busLt-1)*dp.spec.layBusW/2 - dp.spec.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].ch#NIL THEN DP.GetChanY[dp[bigLC.rowBot].ch, kid].loc ELSE bigLC.yBot; IF dp[bigLC.rowBot].ch=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; IF bigLC.horLayBot#CMosB.met2 THEN ERROR; AddPObj[dp.wpo, kid, [tag, loc]]; AddPin[ kid, [tag, loc]]; ENDLOOP}; ENDLOOP } }; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; AddImplicitDecorations: PROC[dp: DP.Form] = { AddImplicitSideDecorations[dp]; AddImplicitEndDecorations[dp]}; AddImplicitSideDecorations: PROC[dp: DP.Form] = { 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].ch#NIL THEN { lss: LSRec; IF NOT RefTab.Fetch[dp[row].ch, actWire].found THEN LOOP; lss _ [loc: DP.GetChanY[dp[row].ch, actWire].loc - dp.spec.met2W/2, size: dp.spec.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.spec.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.spec.pinSize, y: lss.first.size], CMosB.met2]; loc _ [dp.spec.cols*dp.spec.n*BitWidth[dp.spec]- CD.InterestSize[tag].x, dp[row].layY.loc + lss.first.loc]; AddPObj[dp.wpo, actWire, [tag, loc]]; AddPin[ actWire, [tag, loc]] ENDLOOP; ENDLOOP; ENDLOOP}; AddImplicitEndDecorations: PROC[dp: DP.Form] = { 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.spec.pwrW, y: dp.spec.pinSize], CMosB.met]; row: INT _ 0; IF dp.spec.gndBus<=0 THEN RETURN; IF dp.spec.vddBus<=0 THEN ERROR; 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: INT IN [0..dp.spec.n) DO gndx: INT _ BitWidth[dp.spec]*(col*dp.spec.n+bit) + dp.spec.gndBus*dp.spec.layBusW + dp.spec.leftTail - CD.InterestSize[tag].x/2; vddx: INT _ BitWidth[dp.spec]*(col*dp.spec.n+bit) + dp.spec.vddBus*dp.spec.layBusW + dp.spec.leftTail - CD.InterestSize[tag].x/2; 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; IF row = dp.size-1 THEN EXIT ELSE row _ dp.size-1 ENDLOOP}; <> LSs: TYPE = LIST OF LSRec; LSRec: TYPE = RECORD[loc, size: INT]; slop: INT _ CMosB.lambda/2; BitWidth: PUBLIC PROC[spec: DP.DPSpec] RETURNS[bitWidth: INT] = {RETURN[spec.layBusW*spec.buses + spec.layDWidth]}; BitPosX: PUBLIC PROC[spec: DP.DPSpec, col, bit: NAT] RETURNS[pos: INT] = { xform: CoreXform.Xform _ CoreXform.GenXform[(IF spec.interleave THEN LIST[[spec.cols, 1], [spec.n, 0]] ELSE LIST[[spec.cols, 0], [spec.n, 1]] )]; logical: INT _ col*spec.n + bit; RETURN[BitWidth[spec] * CoreXform.XformIndex[xform, lr, logical].i ]}; SchBodyIR: PROC[dp: DP.Form] RETURNS[schIR: CD.Rect] = { schIR _ [ 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]}; SchRowIR: PROC[dp: DP.Form, row: INT] RETURNS[schIR: CD.Rect] = { schIR _ [ x1: dp[row][0].schIR.x1, y1: dp[row][0].schIR.y1, x2: dp[row][dp[0].size-1].schIR.x2, y2: dp[row][dp[0].size-1].schIR.y2]}; GetLayoutCoordSides: PROC[dp: DP.Form, 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.Form, wire: DP.Wire, schIR: CD.Rect, initialLayYSize: BOOL] RETURNS[lc: DP.LayoutCoord] = { OPEN CDB: CDBasics; lc.inBody _ CDB.Intersect[schIR, CDB.Extend[SchBodyIR[dp], -slop-1]]; lc.sides _ GetLayoutCoordSides[dp, schIR]; lc.hor _ GetLayoutHor[schIR]; FOR row: NAT IN [0..dp.size) DO notOutSideRow: BOOL _ CDB.Inside[schIR, CDB.Extend[SchRowIR[dp, row], -slop] ]; IF notOutSideRow AND dp[row].ch#NIL THEN {lc.rowBot _ lc.rowTop _ row; lc.yBot _ lc.yTop _ dp.spec.initialYSize/2; RETURN[lc]}; FOR col: NAT IN [0..dp[row].size) DO 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].ch#NIL THEN RETURN[dp.spec.initialYSize/2, dp.spec.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; leftEdge: INT _ IF col=0 THEN dp[row][col].schIR.x1 ELSE dp[row][col-1].schIR.x2; 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 [leftEdge-slop..dp[row][col].schIR.x1+slop) THEN { lc.colLt _ col; lc.busLt _ 0}; IF schIR.x1 IN [dp[row][col].schIR.x1+slop..dp[row][col].schIR.x2-slop) THEN { lc.colLt _ col; lc.busLt _ SchHalfBus[dp.spec, 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.busRt _ SchHalfBus[dp.spec, schIR.x2-dp[row][col].schIR.x1]}; IF schIR.x2 >= dp[row][col].schIR.x2-slop THEN { lc.colRt _ col; lc.busRt _ sectionRtEdge}; 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.spec.initialYSize ELSE dp[row].layY.size}; ENDLOOP; ENDLOOP}; TrimLayoutCoord: PROC[dp: DP.Form, bigLC: DP.LayoutCoord, row, col: NAT] RETURNS[lc: DP.LayoutCoord] = { lc _ bigLC; IF col > bigLC.colLt THEN lc.busLt _ 0; IF col < bigLC.colRt THEN lc.busRt _ sectionRtEdge ; 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 }; IconToLayoutGeoLocSizes: PROC [sec: DP.Section, actual: DP.Wire, schLoc: INT, side: DP.Side, layer: CD.Layer] RETURNS[lss: LSs] = { VisitBaseSeqCellBinding: PUBLIC PROC [base, seq: DP.Wire] = { IF seq=iconPub THEN {bitCellPub _ base; RETURN}; FOR i: NAT IN [0 .. base.size) WHILE bitCellPub=NIL DO VisitBaseSeqCellBinding[base[i], seq[i]] ENDLOOP}; iconPub: DP.Wire _ GetSchematicPublic[sec.schInst, actual, side, schLoc]; bitCellPub: DP.Wire; bitCell: DP.CellType _ sec.devCells[0]; IF iconPub=NIL THEN Signal[]; VisitBaseSeqCellBinding[bitCell.public, sec.schInst.type.public]; 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]}; 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]}; 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] ] ] ] }}; SchHalfBus: PUBLIC PROC[spec: DP.DPSpec, pos: INT] RETURNS[bus: INT] = { RETURN[pos/(spec.schBusW/2)]}; <> AddPin: PROC [public: DP.Wire, po: DP.PObj] = { pin: CoreGeometry.Instance _ [po.object, [po.position]]; CoreGeometry.AddPins[layDeco, public, LIST[pin]]}; ContPObj: PROC[spec: DP.DPSpec, bus, layY: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = { po.object _ CDSimpleRules.Contact[layRules, CMosB.met, layer]; po.position.x _ spec.leftTail + (bus-1)*spec.layBusW/2 - CD.InterestSize[po.object].x/2; po.position.y _ layY - CD.InterestSize[po.object].x/2}; HorPObj: PROC[spec: DP.DPSpec, layY, lBus, rBus, size: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = { fullW: INT _ BitWidth[spec]; ltEdge: BOOL _ lBus = 0; rtEdge: BOOL _ rBus = sectionRtEdge; x1: INT _ IF ltEdge THEN 0 ELSE spec.leftTail + (lBus-1)*(spec.layBusW/2); x2: INT _ IF rtEdge THEN fullW ELSE spec.leftTail + (rBus-1)*(spec.layBusW/2); <> IF x1 >= x2 THEN Signal[]; po.object _ CDRects.CreateRect[ [x: x2-x1, y: size], layer]; po.position _ [x1, layY - size/2]}; VerPObj: PROC[spec: DP.DPSpec, layYbot, layYtop, bus: INT, size: INT] RETURNS[po: DP.PObj] = { IF layYbot >= layYtop THEN Signal[]; po.object _ CDRects.CreateRect[ [x: size, y: layYtop-layYbot], CMosB.met]; po.position.x _ spec.leftTail + (bus-1)*spec.layBusW/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.Form] 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] = { IF obj=NIL THEN RETURN; loc _ CDBasics.SubPoints[loc, CD.InterestBase[obj]]; 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; FOR row: NAT IN [0..dp.size) DO IF dp[row].ch#NIL THEN { Include[dp[row].obj, [0, dp[row].layY.loc]]; LOOP}; FOR col: NAT IN [0..dp[row].size) DO routing: CD.Object _ CreateRoutingObject[dp, row, col]; FOR bit: INT IN [0..dp.spec.n) DO refPos: CD.Position _ [BitPosX[dp.spec, col, bit] + 0, dp[row].layY.loc]; IF routing#NIL THEN Include[obj: routing, loc: refPos]; IF dp[row][col].devCells#NIL THEN Include[ obj: PWCore.Layout[dp[row][col].devCells[bit]], loc: [x: refPos.x+ dp[row][col].devBOff*dp.spec.layBusW, y: refPos.y]]; ENDLOOP; ENDLOOP; ENDLOOP; [ ] _ RefTab.Pairs[dp.wpo, IncludePins]; cell _ PW.CreateCell[instances: insts, name: name.Cat[".mask"], ir: dp.layIR]}; <<>> CreateRoutingObject: PROC[dp: DP.Form, row, col: 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 _ NARROW[val]; FOR ps: DP.PObjs _ pos, ps.rest WHILE ps#NIL DO ir _ CDBasics.Surround[ ir, CDBasics.MoveRect[CD.InterestRect[ps.first.object], ps.first.position]] ENDLOOP; node _ CDRoutingObjects.CreateNode[pos, LIST [[key: $SignalName, val: name]]]; nodes _ CONS[node, nodes]}; ir: CD.Rect _ [x1: 0, y1: 0, x2: 1, y2: 1]; -- need to begin at 0,0 for easy positioning of object IF RefTab.GetSize[dp[row][col].wpo]=0 THEN RETURN[NIL]; [ ] _ RefTab.Pairs[dp[row][col].wpo, action]; obj _ CDRoutingObjects.CreateRoutingObject[nodes, ir]}; <> <<[nodes, [0, 0, (dp.spec.buses)*dp.spec.layBusW, dp[row].layY.size]]};>> GetDeviceCellTypes: PROC[inst: DP.CellInstance] RETURNS[cells: DP.CellTypeSeq] = { cells _ NEW[DP.CellTypeSeqRec[GetSize[inst.type]]]; FOR i: NAT IN [0..cells.size) DO cells[i] _ GetChild[inst.type, i] ENDLOOP}; GetChild: PROC[cell: DP.CellType, bit: INT] RETURNS[child: DP.CellType] = { 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]]}; GetSize: PROC[cell: DP.CellType] RETURNS[size: INT] = { WITH cell.data SELECT FROM seq: CoreClasses.SequenceCellType => RETURN[seq.count]; rec: CoreClasses.RecordCellType => RETURN[rec.size]; ENDCASE => RETURN[GetSize[ CoreOps.Recast[cell]]]}; <> ShowDP: PUBLIC PROC[dp: DP.Form] = { 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[row].size) 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].ch # NIL => TerminalIO.PutF[" \tChan\t\t"]; mux => TerminalIO.PutF[" \tMux\t"]; ENDCASE => TerminalIO.PutF[" \t\t\t"]; TerminalIO.PutF["%g\n", IO.rope[name]]; ENDLOOP}; IsMux: PROC[cell: DP.CellType] RETURNS[isMux: BOOL] = {RETURN[PWCore.GetLayoutAtom[GetChild[cell, 0]]=$DataPathMux]}; 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]] }; <> RegisterDataPathSpec: PUBLIC PROC[key: IO.ROPE, spec: DP.DPSpec] = {[] _ SymTab.Store[dpKeyTab, key, spec]}; NewCellTypeSpec: PUBLIC PROC[cellType: DP.CellType] RETURNS[spec: DP.DPSpec] = { key: IO.ROPE _ NARROW[CoreProperties.GetCellTypeProp[cellType, $DataPathKey]]; spec _ NEW[DP.DPSpecRec _ FetchDataPathSpecRec[key]]}; FetchDataPathSpecRec: PROC[key: IO.ROPE] RETURNS[spec: DP.DPSpecRec] = { family: IO.ROPE _ key.Substr[0, key.Index[0,"-"]]; busRp: IO.ROPE _ key.Substr[key.Index[0,"-"]+1]; buses: INT _ Convert.IntFromRope[busRp]; sp: DP.DPSpec _ NARROW[SymTab.Fetch[dpKeyTab, family].val]; spec _ sp^; spec.buses _ buses; IF spec.gndBus#-1 THEN spec.gndBus _ spec.gndBus+buses; IF spec.vddBus#-1 THEN spec.vddBus _ spec.vddBus+buses}; <> InitDataPathDP8: PROC = {RegisterDataPathSpec["DP", NEW[DP.DPSpecRec _ [ ]]]}; InitDataPathDP8[]; [] _ PWCore.RegisterLayoutAtom[$DataPath, Layout]; END. <<>>