<> <> <> <> <> <> DIRECTORY CD USING [CreateDrawRef, DrawRectProc, DrawRef, Error, FetchObjectClass, Instance, Layer, Number, ObjectClass, Object, Orientation, Position, Rect, Technology], CDBasics USING [Extend, NonEmpty, universe], CDProperties USING [PutPropOnTechnology, PutProp], CornerStitching USING [Area, ChangeRect, EastEdge, ENorthNeighbour, EnumerateArea, ListArea, ChangeTile, NEastNeighbour, NewTesselation, NorthEdge, PerTileProc, Region, SouthEdge, SWestNeighbour, Tesselation, Tile, Value, WestEdge, WSouthNeighbour], SX, SXAccessInternal, SXAtoms USING [fini, rosePrint, spinifex, thymePrint], SXOutput USING [LinkageHousekeeper, LinkagePrintProc], SXTechnology; SXTechnologyImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDProperties, CornerStitching, SX, SXAccessInternal, SXAtoms EXPORTS SXTechnology SHARES CornerStitching = BEGIN TilePtr: TYPE = REF CornerStitching.Tile; polPtr: REF INT _ NEW[INT]; difPtr: REF INT _ NEW[INT]; chanPtr: REF INT _ NEW[INT]; Post: TYPE ~ RECORD [ r: CD.Rect, l: CD.Layer ]; AddRectParameters: TYPE ~ RECORD [ tes: REF CornerStitching.Tesselation, cir: REF SX.Circuit, PerDrawRect: SXTechnology.PerDrawRectProc, gateNode: REF SX.CircuitNode, postRectList: LIST OF REF Post, clientData: REF ANY ]; AddRectangle: CD.DrawRectProc -- [r: Rect, l: Layer, pr: DrawRef] -- ~ { <<-- I don't care about efficiency here I'm afraid>> data: REF AddRectParameters ~ NARROW[ pr.devicePrivate]; level: SXTechnology.TransistorMaterial ~ data.PerDrawRect[r, l, data.clientData]; IF ~CDBasics.NonEmpty[r] THEN RETURN; SELECT level FROM nothing => NULL; diffusion => { occupants: LIST OF REF CornerStitching.Region _ NARROW[CornerStitching.ListArea[data.tes,r]]; data.tes.ChangeRect[ r, difPtr]; WHILE occupants # NIL DO SELECT occupants.first.value FROM polPtr => data.tes.ChangeRect[ rect~occupants.first.rect, newValue~chanPtr]; chanPtr => data.tes.ChangeRect[ rect~occupants.first.rect, newValue~chanPtr]; ENDCASE; occupants _ occupants.rest ENDLOOP }; polysilicon => { occupants: LIST OF REF CornerStitching.Region _ NARROW[CornerStitching.ListArea[data.tes,r]]; data.tes.ChangeRect[ r, polPtr]; WHILE occupants # NIL DO SELECT occupants.first.value FROM difPtr => data.tes.ChangeRect[ rect~occupants.first.rect, newValue~chanPtr]; chanPtr => data.tes.ChangeRect[ rect~occupants.first.rect, newValue~chanPtr]; ENDCASE; occupants _ occupants.rest ENDLOOP; IF data.gateNode = NIL THEN data.gateNode _ data.cir.AddRect[lev~l, dim~r] ELSE [] _ data.cir.AddRect[lev~l, dim~r, value~data.gateNode]; }; postProcess => { <<-- Save on list and process and enumerate Diffusion nodes in this region later.>> data.postRectList _ CONS[ NEW[Post _ [r~ r, l~ l]], data.postRectList]; }; ENDCASE; -- I guess the end case is implant, well let me tell you one thing I don't deal with implant OK. }; ProcessMosTransistor: PUBLIC PROCEDURE [ appl: CD.Instance, pos: CD.Position, orient: CD.Orientation, cir: REF SX.Circuit, difSpinifex, polSpinifex: SX.SpinifexLayerIndex, difChannel, channelEdge: REF SX.Constraint, difChanSep, difToPolSep: CD.Number, PerDrawRect: SXTechnology.PerDrawRectProc, data: REF ANY _ NIL, PostProcessor: SXTechnology.ReportDifProc _ NIL] RETURNS [gateNode: REF SX.CircuitNode, sourceDrainNodes: LIST OF REF SX.CircuitNode, sourceDrainCount: INTEGER] ~ { <<-- When we get these crazy bent guys well I tell you we just don't know what to do, so we grab ourselves a tile world and plunk it down in that, then maybe we can start to make sense of it.>> FindChannelEdge: CornerStitching.PerTileProc -- [tile: TilePtr, data: REF ANY] RETURNS [REF ANY] -- ~{ occupants, tmp: LIST OF REF CornerStitching.Region; tes: REF CornerStitching.Tesselation ~ NARROW[data]; IF tile.Value = chanPtr THEN { occupants _ NARROW[CornerStitching.ListArea[tes,CDBasics.Extend[tile.Area, difToPolSep]]]; WHILE occupants # NIL DO tmp _ occupants.rest; IF occupants.first.value = difPtr THEN { occupants.rest _ chEdge; chEdge _ occupants }; occupants _ tmp ENDLOOP } }; ConvertMaskGeom: CornerStitching.PerTileProc -- [tile: TilePtr, data: REF ANY] RETURNS [REF ANY] -- ~{ <<-- We are fairly liberal with interest boundaries here, its could be made a lot tighter as is done in the processing of normal Xstrs. All this means is that bent Xstrs will be instantiated for analysis even when they appear in isolation. Acutally this may be what we want since bent transistors are not so constrained that errors are totally precluded in an isolated object (they are for straight Xstrs). Also we let the other code calculate areas and perims, it is likely to be inaccurate.>> SELECT tile.Value FROM difPtr => { CheckChangeAndAdd: PROCEDURE [t: TilePtr] ~ { IF t.Value = difPtr THEN { tranGeom.ChangeTile[ t, node]; [] _ cir.AddRect[ lev~appl.ob.layer, dim~t.Area, value~node] } ELSE WITH t.Value SELECT FROM cn: REF SX.CircuitNode => SX.LookupNode[cn].superceded _ node; <<--Ch. J., Jan 30, 1985 included LookupNode without further thinking>> ENDCASE; }; node: REF SX.CircuitNode _ cir.AddRect[lev~appl.ob.layer, dim~tile.Area]; sdList _ CONS[ node, sdList]; tranGeom.ChangeTile[ tile, node]; FOR st: TilePtr _ tile.WSouthNeighbour, st.NEastNeighbour WHILE st.WestEdge < tile.EastEdge DO CheckChangeAndAdd[ st]; ENDLOOP; FOR wt: TilePtr _ tile.SWestNeighbour, wt.ENorthNeighbour WHILE wt.SouthEdge < tile.NorthEdge DO CheckChangeAndAdd[ wt]; ENDLOOP; FOR nt: TilePtr _ tile.ENorthNeighbour, nt.SWestNeighbour WHILE nt.EastEdge > tile.WestEdge DO CheckChangeAndAdd[ nt]; ENDLOOP; FOR et: TilePtr _ tile.NEastNeighbour, et.WSouthNeighbour WHILE et.NorthEdge > tile.SouthEdge DO CheckChangeAndAdd[ et]; ENDLOOP; }; chanPtr => { [] _ cir.AddBox[ spinifexLayer~difSpinifex, dim~tile.Area, interestBloat~ [difChanSep, difChanSep, difChanSep, difChanSep], value~difChannel]; }; polPtr => NULL; ENDCASE }; AddParm: REF AddRectParameters ~ NEW[AddRectParameters]; tranGeom: REF CornerStitching.Tesselation ~ CornerStitching.NewTesselation[]; sdList: LIST OF REF SX.CircuitNode _ NIL; dr: CD.DrawRef ~ CD.CreateDrawRef[NIL]; chEdge: LIST OF REF CornerStitching.Region _ NIL; AddParm.tes _ tranGeom; AddParm.cir _ cir; AddParm.PerDrawRect _ PerDrawRect; AddParm.gateNode _ NIL; AddParm.postRectList _ NIL; AddParm.clientData _ data; dr.drawRect _ AddRectangle; dr.devicePrivate _ AddParm; appl.ob.class.drawMe[appl, pos, orient, dr]; IF (gateNode _ AddParm.gateNode) = NIL THEN ERROR; [] _ tranGeom.EnumerateArea[ rect~CDBasics.universe, perTile~FindChannelEdge, data~tranGeom]; [] _ tranGeom.EnumerateArea[ rect~CDBasics.universe, perTile~ConvertMaskGeom]; IF PostProcessor # NIL THEN FOR pL: LIST OF REF Post _ AddParm.postRectList, pL.rest WHILE pL # NIL DO FindNodes: CornerStitching.PerTileProc -- [tile: TilePtr, data: REF ANY] RETURNS [REF ANY] -- ~{ <<-- Called for pullups where we can make a sensible decision on which node is the source.>> WITH tile.Value SELECT FROM cn: REF SX.CircuitNode => PostProcessor[cn, pL.first.r, pL.first.l]; ENDCASE }; [] _ tranGeom.EnumerateArea[ rect~pL.first.r, perTile~FindNodes]; ENDLOOP; WHILE chEdge # NIL DO [] _ cir.AddBox[ spinifexLayer~polSpinifex, dim~chEdge.first.rect, value~channelEdge]; chEdge _ chEdge.rest ENDLOOP; sourceDrainNodes _ NIL; sourceDrainCount _ 0; WHILE sdList # NIL DO sdfirst: LIST OF REF SX.CircuitNode ~ sdList; sdList _ sdList.rest; IF sdfirst.first.superceded # NIL THEN LOOP; FOR alreadySeen: LIST OF REF SX.CircuitNode _ sourceDrainNodes, alreadySeen.rest WHILE alreadySeen # NIL DO IF alreadySeen.first = sdfirst.first THEN EXIT; REPEAT FINISHED => { sdfirst.rest _ sourceDrainNodes; sourceDrainNodes _ sdfirst; sourceDrainCount _ sourceDrainCount.SUCC; } ENDLOOP; ENDLOOP; }; SetUpResolution: PUBLIC PROCEDURE [constrArray: REF SX.ConstraintArray, res: SXTechnology.ResolutionTable] RETURNS [REF SX.ConstraintResolution] ~ { Index: TYPE ~ SX.ConstraintIndex; CoreIndex: TYPE ~ [1 .. Index.LAST]; cnsRes: REF SX.ConstraintResolution ~ NEW [SX.ConstraintResolution _ ALL[ALL[NIL]]]; RowUsed, ColumnUsed: ARRAY CoreIndex OF BOOLEAN _ ALL[FALSE]; excl: Index ~ SX.excludeIndex; --2 viol: Index ~ SX.violateIndex; --3 exclusionConstraint: REF SX.Constraint ~ NEW[ SX.Constraint _ [ $ExcludeByOpaqueCell, SX.excludeIndex]]; violationConstraint: REF SX.Constraint ~ NEW[ SX.Constraint _ [ $OpaqueCellViolation, SX.violateIndex]]; <<-- First set up technology independent Opaque cell constraints.>> RowUsed[excl] _ ColumnUsed[excl] _ RowUsed[viol] _ ColumnUsed[viol] _ TRUE; cnsRes[0][excl] _ cnsRes[excl][0] _ exclusionConstraint; cnsRes[0][viol] _ cnsRes[viol][0] _ violationConstraint; FOR i: Index IN [1 .. Index.LAST] DO cnsRes[excl][i] _ cnsRes[i][excl] _ exclusionConstraint; cnsRes[viol][i] _ cnsRes[i][viol] _ violationConstraint; ENDLOOP; cnsRes[excl][excl] _ violationConstraint; <<-- Now copy the elements of constrArray to the first row and column of cnsRes.>> FOR i: Index IN [0..Index.LAST] DO xi: Index ~ res[i][0]; xj: Index ~ res[0][i]; cnsRes[0][i] _ cnsRes[i][0] _ constrArray[i]; <<-- Debugging aid for technology writer.>> IF constrArray[i] # NIL AND i # constrArray[i].index THEN CD.Error[ec~ other, explanation~ "constrArray entry position, index mismatch"]; IF xi # 0 THEN { IF ColumnUsed[xi] THEN CD.Error[ec~ other, explanation~ "Duplicate column key in Constraint Resolution Table"]; ColumnUsed[xi] _ TRUE }; IF xj # 0 THEN { IF RowUsed[xj] THEN CD.Error[ec~ other, explanation~ "Duplicate row key in Constraint Resolution Table"]; RowUsed[xj] _ TRUE }; ENDLOOP; <<-- Debugging aid for technology writer.>> FOR i: CoreIndex IN CoreIndex DO IF RowUsed[i] # ColumnUsed[i] THEN CD.Error[ec~ other, explanation~ "Inconsistencies in Constraint Resolution Table between row & column keys"]; ENDLOOP; FOR i: CoreIndex IN CoreIndex DO xi: Index ~ res[i][0]; IF xi = 0 THEN FOR j: CoreIndex IN CoreIndex DO IF res[i][j] # 0 THEN CD.Error[ec~ other, explanation~ "Inconsistencies in Constraint Resolution Table entries"]; ENDLOOP ELSE FOR j: CoreIndex IN CoreIndex DO xj: Index ~ res[0][j]; IF xj = 0 THEN FOR k: CoreIndex IN CoreIndex DO IF res[k][j] # 0 THEN CD.Error[ec~ other, explanation~ "Inconsistencies in Constraint Resolution Table entries"]; ENDLOOP ELSE { result: Index ~ res[i][j]; IF result = 0 THEN CD.Error[ec~ other, explanation~ "Missing entry in Constraint Resolution Table"]; cnsRes[xi][xj] _ constrArray[ result ] } ENDLOOP ENDLOOP; FOR i: CoreIndex IN CoreIndex DO FOR j: CoreIndex IN CoreIndex DO IF cnsRes[i][j] # cnsRes[j][i] THEN <> CD.Error[ec~ other, explanation~ "Inconsistencies in Constraint Resolution Table entries"]; ENDLOOP ENDLOOP; RETURN [cnsRes] }; RegisterTechnologyHandle: PUBLIC PROCEDURE [cdTech: CD.Technology, technologyHandle: REF SX.TechHandle] ~ { FOR i: SX.SpinifexLayerIndex IN [SX.SpinifexLayerIndex.FIRST .. technologyHandle.numSpinifexLayers) DO IF technologyHandle.constraintResolutions[i] = NIL THEN technologyHandle.constraintResolutions[i] _ defaultResolution; ENDLOOP; CDProperties.PutPropOnTechnology[onto~ cdTech, prop~ SXAtoms.spinifex, val~ technologyHandle]; <> < IF ec = doubleRegistration THEN CONTINUE];>> < IF ec = doubleRegistration THEN CONTINUE];>> < IF ec = doubleRegistration THEN CONTINUE];>> < IF ec = doubleRegistration THEN CONTINUE];>> < IF ec = doubleRegistration THEN CONTINUE];>> }; RegisterSpinifexObjectProcs: PUBLIC PROCEDURE [cdTech: CD.Technology, objectType: ATOM, conv: SX.ConversionProc, thyme, rose: SXOutput.LinkagePrintProc _ NIL, fini: SXOutput.LinkageHousekeeper _ NIL] ~ { op: REF CD.ObjectClass; IF (op_CD.FetchObjectClass[ objectType~objectType, technology~cdTech]) = NIL THEN CD.Error[explanation: "Version mismatch among ChipNDale and Spinifex"]; CDProperties.PutProp[ onto~op.properties, prop~SXAtoms.spinifex, val~ NEW[SX.ConversionProc_conv]]; IF thyme # NIL THEN CDProperties.PutProp[ onto~op.properties, prop~SXAtoms.thymePrint, val~ NEW[SXOutput.LinkagePrintProc_thyme]]; IF rose # NIL THEN CDProperties.PutProp[ onto~op.properties, prop~SXAtoms.rosePrint, val~ NEW[SXOutput.LinkagePrintProc_rose]]; IF fini # NIL THEN CDProperties.PutProp[ onto~op.properties, prop~SXAtoms.fini, val~ NEW[SXOutput.LinkageHousekeeper_fini]]; }; defaultResolution: REF SX.ConstraintResolution; InitDefaultResolution: PROCEDURE ~ { Index: TYPE ~ SX.ConstraintIndex; CoreIndex: TYPE ~ [1 .. Index.LAST]; excl: Index ~ SX.excludeIndex; viol: Index ~ SX.violateIndex; res: REF SX.ConstraintResolution; exclusionConstraint: REF SX.Constraint ~ NEW[ SX.Constraint _ [ $ExcludeByOpaqueCell, SX.excludeIndex]]; violationConstraint: REF SX.Constraint ~ NEW[ SX.Constraint _ [ $OpaqueCellViolation, SX.violateIndex]]; <<-- Set up default technology independent Opaque cell constraints.>> defaultResolution _ NEW[SX.ConstraintResolution]; res _ defaultResolution; res[0][excl] _ res[excl][0] _ exclusionConstraint; res[0][viol] _ res[viol][0] _ violationConstraint; FOR i: CoreIndex IN CoreIndex DO res[excl][i] _ res[i][excl] _ exclusionConstraint; res[viol][i] _ res[i][viol] _ violationConstraint; ENDLOOP; res[excl][excl] _ violationConstraint; }; GetCircuitFromCDObject: PUBLIC PROCEDURE [cdOb: CD.Object] RETURNS [c: REF SX.Circuit_NIL] = BEGIN sx: REF SX.LogicalCell = SXAccessInternal.GetSXData[cdOb]; IF sx#NIL THEN { IF sx.analysisState#useCircuit THEN ERROR; c _ sx.circuit } END; -- Module Initialization. InitDefaultResolution[]; END. <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>>