<> <> <> <> <> <> <<>> 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-NFS"; 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> RETURN [SELECT char FROM '\n, '\l => 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.