DIRECTORY CedarProcess, CifToCD USING [ReadFile], CD, CDCells USING [IsPushedIn], CDDirectory USING [Name], CDImports USING [HasUnloadedImports], CDIO, CDOps, CDSequencer USING [Command], CDSequencerExtras USING [RegisterCommand], CDToCif USING [WriteCIF], CDViewer, Commander, CommandTool, DraculaOps, FS, IO, Process, Real, RealFns, RefTab, Rope, Rsh, SunAuthUnix USING [FixNameForUnix], TerminalIO, ViewerClasses, ViewerOps, UnixRemoteFile, UserCredentials USING [Get]; DraculaOpsImpl: CEDAR PROGRAM IMPORTS CedarProcess, CifToCD, CDCells, CDDirectory, CDImports, CDIO, CDOps, CDSequencerExtras, CDToCif, CDViewer, Commander, CommandTool, FS, IO, Process, Real, RealFns, RefTab, Rope, Rsh, SunAuthUnix, TerminalIO, ViewerOps, UnixRemoteFile, UserCredentials EXPORTS DraculaOps ~ BEGIN ROPE: TYPE = Rope.ROPE; DRCData: TYPE = REF DRCDataRec; DRCDataRec: TYPE = RECORD [instance: CD.Instance, design: CD.Design, rules: Rope.ROPE]; fileHost: ROPE _ "velantia"; cpuHost: ROPE _ "velantia"; remoteServerDir: ROPE _ "/tmp/"; ecadCmd: ROPE _ "/usr/ecad/bin/dracula "; description: ROPE _ "\l*DESCRIPTION\lPRIMARY = %g\lWINDOW = %d %d %d %d\lPROGRAM-DIR = /usr/ecad/\lSYSTEM = CIF\lSCALE = 0.01 MIC\lRESOLUTION = 0.25 MIC\lFLAG-OFFGRID = YES\lINDISK = %g.cif\lOUTDISK = %g.errors.cif\lKEEPDATA = SMART\lMODE = EXEC NOW\lSYSOUT = CIF\lSCALEOUT = 0.25 MIC\lPRINTFILE = drclog\l*END\l"; overlap: REAL _ 50.0; -- microns eachJobSize: REAL _ 5.0e7; -- = 0.5cm2 drcTab: RefTab.Ref _ RefTab.Create[]; defaultRulesName: ROPE _ "VTI"; cifExt: ROPE _ ".cif"; descrExt: ROPE _ ".des"; errorsExt: ROPE _ ".errors.cif"; logFile: ROPE _ "DRCLOG.SUM"; --highly flexible name cifPerLambda: INT _ 100; flattenAtomics: BOOLEAN _ TRUE; ecadKey: ATOM _ $EcadErrorsCif; --to identify the set of cif conventions DRCInstance: PUBLIC PROC [instance: CD.Instance, design: CD.Design, rules: Rope.ROPE] RETURNS [reportMsg: Rope.ROPE _ NIL, hasErrors: BOOLEAN _ TRUE] ~ { drcData: DRCData _ NEW[DRCDataRec _ [instance, design, rules]]; reportMsg _ NARROW[DoDRCInstance[drcData]]; hasErrors _ reportMsg.Length[]#0}; DoDRCInstance: PROC [data: REF] RETURNS [result: REF _ NIL] ~ { reportMsg: Rope.ROPE; instance: CD.Instance; design: CD.Design; rules: Rope.ROPE; fileServer: UnixRemoteFile.UnixServerHandle _ UnixRemoteFile.CreateHandle[fileHost]; myName: Rope.ROPE _ SunAuthUnix.FixNameForUnix[UserCredentials.Get[].name]; workingDir: Rope.ROPE _ Rope.Cat[remoteServerDir, myName]; [instance, design, rules] _ NARROW[data, DRCData]^; { ENABLE ABORTED, Process.InvalidProcess => { reportMsg _ "DRC ABORTED"; GOTO Failed }; CatchOne: UnixRemoteFile.EachNameProc ~ { IF Rope.Fetch[name, 0]#'. THEN victimList _ CONS[Rope.Cat[workingDir, "/", name], victimList]; }; victimList: LIST OF ROPE; topCellName, fileName: ROPE; remoteFile, log: IO.STREAM; sizeX, sizeY, minX, minY, maxX, maxY: REAL; nX, nY: NAT; hasErrors: BOOLEAN _ FALSE; lambda: REAL _ design.technology.lambda; -- conversion from INT dx: REAL _ (instance.ob.bbox.x2-instance.ob.bbox.x1)/lambda; ox: REAL _ instance.ob.bbox.x1/lambda; dy: REAL _ (instance.ob.bbox.y2-instance.ob.bbox.y1)/lambda; oy: REAL _ instance.ob.bbox.y1/lambda; topCellName _ CDDirectory.Name[instance.ob, design]; IF topCellName=NIL THEN {reportMsg _ "Impossible to DRC non named objects"; GOTO Failed;}; UnixRemoteFile.MkDir[fileServer, [workingDir], 0666B ! UnixRemoteFile.Error => { IF code=$exist THEN { TerminalIO.PutRope[Rope.Cat["Dracula Warning: ", fileHost, ":", workingDir, " already exists\n"]]; CONTINUE; } ELSE { reportMsg _ IO.PutFR["Dracula Error: %g (%g)\n", IO.rope[msg], IO.atom[code]]; GOTO Failed; } }]; fileName _ Rope.Cat[workingDir, "/", topCellName, cifExt]; remoteFile _ UnixRemoteFile.OpenWriteStream[fileServer, [fileName], 0666B ! UnixRemoteFile.Error => {reportMsg _ IO.PutFR["WriteError: %g (%g)\n", IO.rope[msg], IO.atom[code]]; GOTO Failed;}]; TerminalIO.PutRopes["Dracula DRC. CIF file: ", fileName, "\n"]; reportMsg _ CDToCif.WriteCIF[design, instance, remoteFile, cifPerLambda, flattenAtomics]; IO.Close[remoteFile]; IF reportMsg#NIL THEN GOTO Failed; [sizeX, sizeY, nX, nY] _ GetJobSize[dx, dy]; minX _ ox-overlap; maxX _ ox+sizeX+overlap; THROUGH [0..nX) DO minY _ oy-overlap; maxY _ oy+sizeY+overlap; THROUGH [0..nY) DO fileName _ Rope.Cat[workingDir, "/", topCellName, descrExt]; remoteFile _ UnixRemoteFile.OpenWriteStream[fileServer, [fileName], 0666B ! UnixRemoteFile.Error => {reportMsg _ IO.PutFR["WriteError: %g (%g)\n", IO.rope[msg], IO.atom[code]]; GOTO Failed;}]; IO.PutFL[stream: remoteFile, format: description, list: LIST[ [rope[topCellName]], -- PRIMARY = cellName [real[minX]], [real[minY]], [real[maxX]], [real[maxY]], --WINDOW x1 y1 x2 y2 [rope[topCellName]], -- INDISK = %g.cif [rope[topCellName]] ]]; -- OUTDISK = %g.errors.cif IO.Close[remoteFile]; log _ FS.StreamOpen[fileName: Rope.Cat[topCellName, ".log"], accessOptions: create]; IF nX#1 OR nY#1 THEN TerminalIO.PutF["Dracula: Now DRCing [%d, %d, %d, %d]\n", [real[minX]], [real[minY]], [real[maxX]], [real[maxY]]]; reportMsg _ Rsh.RSH[ remoteMachine: cpuHost, command: Rope.Cat[Rope.Cat["cd ", workingDir, "; "], ecadCmd, topCellName, " ", rules], --i.e. cd /tmp/lecocq/; /usr/ecad/bin/dracula thisCell VTI in: IO.noInputStream, out: log, error: TerminalIO.TOS[] ]; IO.Close[log]; IF reportMsg#NIL THEN GOTO Failed; fileName _ Rope.Cat[workingDir, "/", logFile]; remoteFile _ UnixRemoteFile.OpenReadStream[fileServer, [fileName] ! UnixRemoteFile.Error => {reportMsg _ IO.PutFR["ReadError: %g (%g)\n", IO.rope[msg], IO.atom[code]]; GOTO Failed;}]; IF CheckForErrors[remoteFile ! IO.Error, IO.EndOfStream => {reportMsg _ "Bad or no DRCSUM file";GOTO Failed;}] THEN { fileName _ Rope.Cat[workingDir, "/", topCellName, errorsExt]; remoteFile _ UnixRemoteFile.OpenReadStream[fileServer, [fileName] ! UnixRemoteFile.Error => {reportMsg _ IO.PutFR["ReadError: %g (%g)\n", IO.rope[msg], IO.atom[code]]; CONTINUE;}]; IF reportMsg#NIL THEN GOTO Failed; reportMsg _ CifToCD.ReadFile[remoteFile, design, ecadKey, instance.trans]; IF reportMsg#NIL THEN GOTO Failed; hasErrors _ TRUE; }; minY _ minY+sizeY; maxY _ maxY+sizeY; ENDLOOP; minX _ minX+sizeX; maxX _ maxX+sizeX; ENDLOOP; IF hasErrors THEN CDOps.RedrawInstance[design, instance] ELSE TerminalIO.PutRope["\n*\n* Dracula: No DRC Errors !\n*\n"]; UnixRemoteFile.Enumerate[fileServer, [workingDir], "*", CatchOne]; UNTIL victimList=NIL DO UnixRemoteFile.Delete[fileServer, [victimList.first]]; victimList _ victimList.rest; ENDLOOP; UnixRemoteFile.RmDir[fileServer, [workingDir]] EXITS Failed => {TerminalIO.PutRope[reportMsg]; result _ reportMsg;} }; UnixRemoteFile.DestroyHandle[fileServer]; [] _ RefTab.Delete[drcTab, instance]; }; GetJobSize: PROC [dx, dy: REAL] RETURNS [sizeX, sizeY: REAL, nX, nY: NAT] ~ { bigFactor, smallFactor, nTimes: NAT; nTimes _ Real.Ceiling[dx*dy/eachJobSize]; smallFactor _ GetDiv[nTimes]; bigFactor _ nTimes/smallFactor; IF dx sepr, ENDCASE => other] }; MyGetLineRope: PROC [s: IO.STREAM] RETURNS [r: ROPE] ~ INLINE { RETURN[IO.GetTokenRope[stream: s, breakProc: IsEOL].token] }; CheckForErrors: PROC [logFile: IO.STREAM] RETURNS [hasErrors: BOOLEAN _ FALSE] ~ { startText: ROPE _ "(LINE SEGMENTS)"; stopText: ROPE _ "PRIMARY CELL :"; l: Rope.ROPE _ NIL; UNTIL Rope.Find[s1: l, s2: startText]#-1 DO l _ MyGetLineRope[logFile]; ENDLOOP; [] _ IO.SkipWhitespace[logFile]; l _ MyGetLineRope[logFile]; UNTIL Rope.Find[s1: l, s2: stopText]#-1 DO hasErrors _ TRUE; TerminalIO.PutRopes[l, "\n"]; [] _ IO.SkipWhitespace[logFile]; l _ MyGetLineRope[logFile]; ENDLOOP; }; doc: IO.ROPE _ "DraculaDRC designName [rules]\n"; DraculaDRCProc: Commander.CommandProc = { Fail: PROC[msg: IO.ROPE] RETURNS[atom: ATOM _ $Failure] = {cmd.out.PutF["%g\n%g\n", IO.rope[msg], IO.rope[doc]]}; name: IO.ROPE _ CommandTool.ArgN[cmd, 1]; design: CD.Design _ GetDesign[name]; insts: CD.InstanceList; rules: IO.ROPE _ "VTI"; reportMsg: IO.ROPE _ NIL; hasErrors: BOOL _ TRUE; name _ name.Substr[0, name.Index[0, "."]]; IF design=NIL THEN {cmd.out.PutRope[doc]; RETURN[$Failure]}; IF design#NIL THEN insts _ CDOps.InstList[design]; SELECT TRUE FROM design=NIL => {RETURN[Fail["*** Design not found."]]}; insts=NIL => {RETURN[Fail["*** Design empty."]]}; insts.rest#NIL => {RETURN[Fail["*** Design has multiple instances."]]}; ENDCASE; IF rules.Length[]=0 THEN rules _ "VTI"; [reportMsg, hasErrors] _ DRCInstance[insts.first, design, rules]; IF hasErrors THEN cmd.out.PutF["*** DRC Errors\n %g\n", IO.rope[reportMsg]] ELSE cmd.out.PutRope[" No DRC Errors\n\n"]}; GetDesign: PUBLIC PROC [name: IO.ROPE] RETURNS [design: CD.Design] = { viewer: ViewerClasses.Viewer; design _ CDViewer.FindDesign[name]; IF design#NIL THEN RETURN[design]; IF name.Length[]=0 THEN RETURN[NIL]; design _ CDIO.ReadDesign[name]; CDOps.SetMutability[design]; viewer_CDViewer.CreateViewer[design, FALSE]; ViewerOps.CloseViewer[viewer]}; DraculaDRCCmd: PROC [comm: CDSequencer.Command] ~ { drcData: DRCData; mainInst: CD.Instance; IF CDCells.IsPushedIn[comm.design] THEN { TerminalIO.PutRope["**Design is pushed in\n"]; GOTO Exit }; IF CDImports.HasUnloadedImports[comm.design].yes THEN { TerminalIO.PutRope["**Design has unbound imports\n"]; GOTO Exit }; mainInst _ CDOps.TheInstance[comm.design, "cif generation\n"]; IF mainInst=NIL THEN { TerminalIO.PutRope["**CIF generation needs single selected object\n"]; GOTO Exit }; drcData _ NEW[DRCDataRec _ [mainInst, comm.design, defaultRulesName]]; [] _ RefTab.Store[drcTab, mainInst, CedarProcess.Fork[DoDRCInstance, drcData,[background, TRUE, TRUE]]]; TerminalIO.PutRope["Dracula started\n"]; EXITS Exit => {}; }; DraculaAbortCmd: PROC [comm: CDSequencer.Command] ~ { GetIt: RefTab.EachPairAction ~ { found _ TRUE; value _ val; }; found: BOOLEAN _ FALSE; value: RefTab.Val; mainInst: CD.Instance _ CDOps.TheInstance[comm.design, "drc delete\n"]; IF mainInst#NIL THEN [found, value] _ RefTab.Fetch[x: drcTab, key: mainInst]; IF NOT found AND RefTab.GetSize[drcTab]=1 THEN [] _ RefTab.Pairs[drcTab, GetIt]; IF found THEN { process: CedarProcess.Process _ NARROW[value]; IF process.status=busy THEN TRUSTED {Process.Abort[process.process]}; TerminalIO.PutRope[" DRC Abort requested\n"]; } ELSE { IF RefTab.GetSize[drcTab]=0 THEN TerminalIO.PutRope[" no DRC pending\n"] ELSE TerminalIO.PutRope[" multiple DRCs pending, select one instance\n"]; } }; CDSequencerExtras.RegisterCommand[key: $DraculaDrc, proc: DraculaDRCCmd, queue: doQueue]; CDSequencerExtras.RegisterCommand[key: $DraculaDel, proc: DraculaAbortCmd, queue: doQueue]; TerminalIO.PutRope["DraculaOps loaded\n"]; Commander.Register[key:"DraculaDRC", proc: DraculaDRCProc, doc: doc]; END.  DraculaOpsImpl.mesa Copyright Σ 1987, 1988 by Xerox Corporation. All rights reserved. Christian Le Cocq April 25, 1988 1:43:37 pm PDT Jean-Marc Frailong December 28, 1987 3:38:44 pm PST Last Edited by: Ross March 20, 1987 5:23:14 pm PST Don Curry July 6, 1988 7:38:58 pm PDT these four are Unix side dependant description: ROPE _ " *DESCRIPTION PRIMARY = %g WINDOW = %d %d %d %d PROGRAM-DIR = /usr/ecad/ SYSTEM = CIF SCALE = 0.01 MIC RESOLUTION = 0.25 MIC FLAG-OFFGRID = YES INDISK = %g.cif OUTDISK = %g.errors.cif KEEPDATA = SMART MODE = EXEC NOW SYSOUT = CIF SCALEOUT = 0.25 MIC PRINTFILE = drclog *END "; DRC control [char: CHAR] RETURNS [IO.CharClass] CommandTool Command CD Commands Called by ChipNDale upon activation of the command. Called by ChipNDale upon activation of the command. Κ ˜šœ™JšœB™BIcode™/K™3K™2K™%—J™šΟk ˜ Kšœ ˜ Kšœœ ˜Kšœ˜Kšœœ˜Kšœ œ˜Kšœ œ˜%Kšœ˜Kšœ˜Kšœ œ ˜Kšœœ˜*Kšœœ ˜Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜J˜J˜J˜J˜Jšœ˜Jšœ˜Jšœ œ˜#Jšœ ˜ Jšœ˜Jšœ˜Jšœœ˜J˜—šΠblœœ˜Kšœƒœœp˜Kšœ ˜Kšœ˜K˜Kšœœœ˜šœ œœ ˜Kš œ œœ œœœ˜W—K˜K™"Kšœ œ˜Kšœ œ˜Kšœœ ˜ Kšœ œ˜)K˜Kšœ œ˜™©Kšœ œ©˜ΊKšœ œ Οc ˜ Kšœ œ Ÿ Πcu˜&K˜K˜%Kšœœ ˜Kšœœ ˜Kšœ œ ˜Kšœ œ˜ Kšœ œŸ˜4Kšœœ˜Kšœœœ˜Kšœ œŸ(˜H—head™ šΟn œœœ œœœœœœ œœ˜™Jšœœ)˜?Jšœ œ˜+Jšœ"˜"K˜—š ‘ œœœœ œœ˜?Kšœœ˜Kšœ œ ˜Kšœœ˜Kšœ œ˜KšœT˜TKšœ œ:˜KKšœœ%˜:Kšœœ˜3˜šœœ˜+Kšœ˜Jšœ˜ Kšœ˜—š‘œ!˜)Kšœœœ.˜^K˜—Kšœ œœœ˜Kšœœ˜Kšœœœ˜Kšœ&œ˜+Kšœœ˜ Kšœ œœ˜KšœœŸ˜?Kšœœ4˜[s1: ROPE, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE]šœœ˜ Kšœœ˜šœ#˜*Kšœ œ˜Kšœ˜K–>[s1: ROPE, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE]šœœ˜ Kšœœ˜Kšœ˜—K˜——™JšœœœΠbn œ˜1J˜š’ ‘œ˜)š œœœœœœ˜9Jšœœ œ ˜7—Jšœœœ˜,Jšœ œ˜%Jšœ œ˜Jšœ œœ ˜Jšœ œœœ˜Jšœ œœ˜Jšœ*˜*Jšœ œœ ˜˜>šœ œœ˜KšœF˜FKšœ˜ K˜—Kšœ œ9˜Fšœ$˜$Jšœ6œœ˜E—Kšœ(˜(Kšœ ˜Kšœ˜K˜—š’œœ ˜5K™3š‘œ˜ Kšœœ˜ Kšœ ˜ K˜—Kšœœ˜Kšœ˜Kšœ œ;˜GJ–$[x: RefTab.Ref, key: RefTab.Key]šœ œœ9˜MJ–2[x: RefTab.Ref, action: RefTab.EachPairAction]šœœœœ"˜Pšœœ˜Jšœ œ˜.Jšœœœ"˜EKšœ-˜-K˜—šœ˜Kšœœ(˜HKšœE˜IK˜—Kšœ˜K˜—JšœY˜YJšœ[˜[Kšœ*˜*K˜JšœE˜EK˜Kšœ˜——…—+Z>„