<> <> <> <> DIRECTORY CD, CDBasics, CDCommandOps, CDErrors, CDMenus, CDOrient, CDProperties, CDSequencer, CDSimpleRules, CornerStitching, IO, Rope, TerminalIO; CDWellTestCommand: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCommandOps, CDErrors, CDMenus, CDOrient, CDProperties, CDSequencer, CDSimpleRules, CornerStitching, IO, TerminalIO = BEGIN wellContMaxDistInLambda: INT _ 75; --in lambda (assume 75 mu, 1 lambda = 1 mu) StateRec: TYPE = RECORD [ <<--the original nwell tesselation>> nwell: CD.Layer, wellTess: REF CornerStitching.Tesselation _ NIL, <<--for unify Node>> nodeFound: REF NodeRec _ NIL, <<--the copied nwell tesselation>> wellTess2: REF CornerStitching.Tesselation _ NIL, <<--the wellcontact>> nwellcont: CD.Layer, growDist: CD.Number, <<--reporting errors>> design: CD.Design, inst: CD.Instance, errorCount: INT _ 0 ]; NodeRec: TYPE = RECORD [ refer: REF NodeRec _ NIL ]; WellCheckCommand: PROC [comm: CDSequencer.Command] = BEGIN inst: CD.Instance; inst _ CDCommandOps.TheInstance[comm: comm, text: "check well contacts"]; IF inst#NIL THEN { no: INT; no _ CheckAGlobalInstance[comm.design, inst].errNo; TerminalIO.WriteF[" well contact check found %g problems\n", IO.int[no]]; }; END; DrawInstance: PROC [pr: CD.DrawRef, inst: CD.Instance] = BEGIN pr.drawChild[inst, inst.location, inst.orientation, pr]; END; CheckAGlobalInstance: PROC [design: CD.Design, inst: CD.Instance] RETURNS [errNo: INT] = BEGIN dist: CD.Number _ wellContMaxDistInLambda*design.technology.lambda; pr: CD.DrawRef _ CD.CreateDrawRef[design]; state: REF StateRec _ NEW[StateRec_[ nwell: CDSimpleRules.GetLayer[design.technology, $nwell], nwellcont: CDSimpleRules.GetLayer[design.technology, $nwelCont], growDist: dist, wellTess: CornerStitching.NewTesselation[], design: design, inst: inst, errorCount: 0 ]]; CDErrors.RemoveMessages[design: state.design, ob: state.inst.ob, owner: errorOwner]; pr.devicePrivate _ state; pr.drawRect _ DrawNWellTess; DrawInstance[pr, inst]; state.wellTess2 _ MakeCopy[state.wellTess]; pr.drawRect _ SubtractBlownContact; DrawInstance[pr, inst]; CornerStitching.EnumerateArea[plane: state.wellTess, rect: CDBasics.universe, perTile: ReportError, data: state]; errNo _ state.errorCount; END; GetRealNode: PROC [n: REF NodeRec] RETURNS [rn: REF NodeRec_NIL] = <<--and simplify refer path>> BEGIN IF n#NIL THEN { IF n.refer=NIL THEN rn _ n ELSE { rn _ GetRealNode[n.refer]; n.refer _ rn } }; END; Unify: PROC [a, b: REF NodeRec] RETURNS [REF NodeRec] = <<--both#NIL, a#b>> BEGIN ra: REF NodeRec _ GetRealNode[a]; rb: REF NodeRec _ GetRealNode[b]; IF ra#rb THEN ra.refer _ rb; RETURN [rb]; END; UnifyNodes: CornerStitching.PerTileProc = BEGIN state: REF StateRec _ NARROW[data]; WITH tile.value SELECT FROM nd: REF NodeRec => { IF state.nodeFound=NIL THEN state.nodeFound _ nd ELSE IF state.nodeFound#nd THEN state.nodeFound _ Unify[state.nodeFound, nd] }; ENDCASE => NULL END; DrawNWellTess: PROC [r: CD.Rect, l: CD.Layer, pr: CD.DrawRef] = BEGIN state: REF StateRec _ NARROW[pr.devicePrivate]; IF state.nwell=l THEN { state.nodeFound _ NIL; CornerStitching.EnumerateArea[plane: state.wellTess, rect: CDBasics.Extend[r, 1], perTile: UnifyNodes, data: state]; IF state.nodeFound=NIL THEN state.nodeFound _ NEW[NodeRec]; CornerStitching.ChangeRect[plane: state.wellTess, rect: r, newValue: GetRealNode[state.nodeFound]]; }; END; SubtractBlownContact: PROC [r: CD.Rect, l: CD.Layer, pr: CD.DrawRef] = BEGIN state: REF StateRec _ NARROW[pr.devicePrivate]; IF l=state.nwellcont THEN { t: REF CornerStitching.Tile _ CornerStitching.TileAt[state.wellTess2, CDBasics.Center[r]]; WITH t.value SELECT FROM rn: REF NodeRec => { state.nodeFound _ rn; CornerStitching.FuncChangeRect[plane: state.wellTess, rect: CDBasics.Extend[r, state.growDist], perTile: SubtractConnection, data: state]; }; ENDCASE => IncludeErrorMessage[state, r, "well missing"] }; END; SubtractConnection: CornerStitching.PerTileChangeProc = BEGIN state: REF StateRec _ NARROW[data]; WITH oldValue SELECT FROM rn: REF NodeRec => { IF GetRealNode[rn]=GetRealNode[state.nodeFound] THEN { CornerStitching.ChangeRect[plane: state.wellTess, rect: rect, newValue: NIL]; } }; ENDCASE => NULL; END; ReportError: CornerStitching.PerTileProc = BEGIN state: REF StateRec _ NARROW[data]; IncludeErrorMessage[state, CornerStitching.Area[tile], "N-Well contact missing"]; END; MakeCopy: PROC [t: REF CornerStitching.Tesselation] RETURNS [new: REF CornerStitching.Tesselation] = BEGIN new _ CornerStitching.NewTesselation[]; CornerStitching.EnumerateArea[plane: t, rect: CDBasics.universe, perTile: CopyTile, data: new] END; CopyTile: CornerStitching.PerTileProc = BEGIN into: REF CornerStitching.Tesselation _ NARROW[data]; nr: REF NodeRec _ NARROW[tile.value]; CornerStitching.ChangeRect[plane: into, rect: CornerStitching.Area[tile], newValue: GetRealNode[nr]] END; IncludeErrorMessage: PROC [state: REF StateRec, rect: CD.Rect, msg: Rope.ROPE] = <<--rect in world coordinates>> BEGIN r: CD.Rect _ CDOrient.DeMapRect[itemInWorld: rect, cellSize: state.inst.ob.size, cellInstOrient: state.inst.orientation, cellInstPos: state.inst.location ]; state.errorCount _ state.errorCount+1; [] _ CDErrors.IncludeMessage[design: state.design, ob: state.inst.ob, rect: r, message: msg, owner: errorOwner]; END; errorOwner: ATOM _ $WellProblem; [] _ CDProperties.RegisterProperty[errorOwner, $chj]; CDMenus.CreateEntry[menu: $ProgramMenu, entry: "Check well contacts", key: $WellContactsCheck]; CDSequencer.ImplementCommand[a: $WellContactsCheck, p: WellCheckCommand, queue: doQueue]; END.