<> <> <> DIRECTORY Basics, CD, CDBasics, CDCellsInteractions, CDDirectory, CDIO, CDOps, CDViewer, CedarProcess, CMosB, Commander, CommandTool, Core, CoreClasses, CoreGeometry, CoreFlat, CoreOps, CoreProperties, DAUser, DraculaOps, IO, Mint, Nodeness, PW, PWCore, PWCoreLichen, Real, RealFns, Rope, RosemaryUser, RoutingCheck, Sinix, SinixOps, Sisyph, Static, SymTab, TerminalIO, ViewerClasses, ViewerOps; CheckDesign: CEDAR PROGRAM IMPORTS Basics, CD, CDBasics, CDCellsInteractions, CDDirectory, CDIO, CDOps, CDViewer, CedarProcess, CMosB, Commander, CommandTool, CoreOps, CoreProperties, DAUser, DraculaOps, IO, Mint, Nodeness, PW, PWCore, PWCoreLichen, Real, RealFns, Rope, RosemaryUser, RoutingCheck, SinixOps, Sisyph, Static, SymTab, TerminalIO, ViewerOps = BEGIN <> Handle: TYPE = REF HandleRec; HandleRec: TYPE = RECORD [ designNm: IO.ROPE _ NIL, schNm: IO.ROPE _ NIL, schDesign: CD.Design _ NIL, layDesign: CD.Design _ NIL, cells: Cells _ NIL ]; Cells: TYPE = LIST OF Core.CellType; log: IO.STREAM _ TerminalIO.TOS[]; layMode: Sinix.Mode = PWCore.extractMode; schMode: Sinix.Mode = Sisyph.mode; doc: IO.ROPE _ "CheckDesign designName \n"; <> CheckDesignCmdProc: Commander.CommandProc = { Log: PROC[r: IO.ROPE] = {cmd.out.PutRope[r]; log.PutRope[r]}; LogDone: PROC = {Log[IO.PutFR["done %g\n", IO.time[]]]}; h: Handle _ InitHandle[cmd]; initialPriority: CedarProcess.Priority _ CedarProcess.GetPriority[]; cellPrintNm: IO.ROPE; IF h=NIL THEN {cmd.out.PutRope[doc]; RETURN[$Failure]}; cellPrintNm _ IF h.schNm=NIL THEN "--ALL--" ELSE h.schNm; CedarProcess.SetPriority[background]; Log[IO.PutFR["%l\n", IO.rope["f"]]]; Log[IO.PutFR["Check Design: %g\n", IO.rope[h.designNm]]]; Log[IO.PutFR[" Cell: %g\n", IO.rope[cellPrintNm]]]; Log[IO.PutFR[" start %g\n", IO.time[]]]; Log[" Extract Src ... "]; ExtractSrc [h]; LogDone[]; Log[" Gen Lay ... "]; GenLayout [h]; LogDone[]; Log[" Extract Lay ... "]; ExtractLay [h]; LogDone[]; Log[" Lichen Ck ... "]; LichenCk [h]; LogDone[]; Log[" Static Ck ... "]; StaticCk [h]; LogDone[]; Log[" Mint Ck ... "]; MintCk [h]; LogDone[]; Log[" Sim Ck ... "]; SimCk [h]; LogDone[]; Log[" Conn Ck ... "]; ConnectCk [h]; LogDone[]; Log[" DRC Ck ... "]; DRCDesign [h]; LogDone[]; CedarProcess.SetPriority[initialPriority]}; <> InitHandle: PROC[cmd: Commander.Handle] RETURNS[h: Handle] = { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd]; schNm: IO.ROPE _ NIL; h _ NEW[HandleRec _ []]; h.designNm _ CommandTool.ArgN[cmd, 1]; h.schDesign _ GetDesign[h.designNm]; IF h.schDesign=NIL THEN { cmd.out.PutF["\nCan't find design %g\n", IO.rope[h.designNm]]; RETURN[NIL]}; CDCellsInteractions.PopToTopLevel[h.schDesign]; h.schNm _ schNm _ CommandTool.ArgN[cmd, 2]; IF schNm#NIL THEN { IF CDDirectory.Fetch[h.schDesign, h.schNm]#NIL THEN RETURN[h]; h.schNm _ schNm.Cat[".icon"]; IF CDDirectory.Fetch[h.schDesign, h.schNm]#NIL THEN RETURN[h]; h.schNm _ schNm.Cat[".sch"]; IF CDDirectory.Fetch[h.schDesign, h.schNm]#NIL THEN RETURN[h]; cmd.out.PutF["\nCan't find cell %g\n", IO.rope[schNm]]; RETURN[NIL]}}; ExtractSrc: PROC[h: Handle] = { cx: Sisyph.Context _ Sisyph.Create[h.schDesign]; IF h.schNm#NIL THEN h.cells _ LIST[Sisyph.ES[h.schNm, cx]] ELSE { list: Cells; SelectObjectsForExtraction[h.schDesign]; list _ SinixOps.SelectedCellTypes[h.schDesign, schMode]; IF list = NIL THEN ERROR; FOR list _ list, list.rest WHILE list#NIL DO h.cells _ CONS[list.first, h.cells] ENDLOOP} }; GenLayout: PROC[h: Handle] = { FOR list: Cells _ h.cells, list.rest WHILE list#NIL DO IF HasLayout[list.first] THEN []_PWCore.Layout[list.first] ENDLOOP}; ExtractLay: PROC[h: Handle] = { FOR list: Cells _ h.cells, list.rest WHILE list #NIL DO ect: Core.CellType; IF ~HasLayout[list.first] THEN LOOP; log.PutF["\nLayout Extraction of %g.\n",IO.rope[CoreOps.GetCellTypeName[list.first]]]; ect _ PWCore.LayoutInfo[list.first].extractedCT ENDLOOP}; SimCk: PROC[h: Handle] = { FOR list: Cells _ h.cells, list.rest WHILE list #NIL DO IF CoreProperties.GetCellTypeProp[list.first, $Tests]#NIL THEN { tester: RosemaryUser.Tester _ DAUser.RunRosemary[list.first, h.schDesign]; log.PutF["\nSimulation Check of %g.\n",IO.rope[CoreOps.GetCellTypeName[list.first]]]; RosemaryUser.StartTest[tester]} ENDLOOP}; MintCk: PROC[h: Handle] = { FOR list: Cells _ h.cells, list.rest WHILE list #NIL DO MintCheck[list.first] ENDLOOP}; MintCheck: PROC[cell: Core.CellType, useLayoutIfPresent: BOOL _ TRUE] = { GetNode: PROC[name: IO.ROPE] RETURNS[node: Mint.Node _ NIL] = { IF CoreOps.FindWire[cell.public, name]#NIL THEN node _ Mint.NodeFromRope[Rope.Cat["public.", name], circuit]}; GenClkNodeList: PROC[names: LIST OF IO.ROPE] RETURNS[list: Mint.NodeList] = { IF names=NIL THEN RETURN[NIL] ELSE { hiNm: IO.ROPE _ names.first; loNm: IO.ROPE _ Rope.Cat["n", names.first]; node: Mint.Node; list _ GenClkNodeList[names.rest]; IF (node _ GetNode[hiNm])#NIL THEN {log.PutF["Mint Clock: %g\n", IO.rope[hiNm]]; list _ CONS[node, list]}; IF (node _ GetNode[loNm])#NIL THEN {log.PutF["Mint Clock: %g\n", IO.rope[loNm]]; list _ CONS[node, list]} }}; defaultCapa: REAL _ 0.5; circuit: Mint.Circuit _ Mint.CreateCircuit[cell]; clockNames: LIST OF IO.ROPE _ LIST["Clock","Clk","Ck","CK","PhA","PhB","phA","phB"]; clocks: Mint.NodeList _ GenClkNodeList[clockNames]; vddNode: Mint.Node _ GetNode["Vdd"]; gndNode: Mint.Node _ GetNode["Gnd"]; slowNodes: Mint.PathArray; lastTime: Mint.ps; veryLastTime: Mint.ps; name: IO.ROPE _ CoreOps.GetCellTypeName[cell]; layout: BOOL _ useLayoutIfPresent AND HasLayout[cell]; log.PutF["\nMint Check of %g %g.\n", IO.rope[CoreOps.GetCellTypeName[cell]], IO.rope[IF layout THEN "layout" ELSE "source"]]; IF vddNode=NIL AND gndNode=NIL THEN {log.PutF["Cell: %g is missing a power connection.\n", IO.rope[name]]; RETURN}; Mint.SetNode[vddNode, TRUE]; Mint.SetNode[gndNode, FALSE]; Mint.InputData[circuit, LIST[gndNode, vddNode], layout, defaultCapa]; Mint.CheckLibrary[circuit]; Mint.OutputResults[circuit]; lastTime _ Mint.RecordPaths[circuit, clocks]; log.PutF["Longest time: %4.1fns\n", IO.real[lastTime/1000.0]]; [veryLastTime, slowNodes] _ Mint.FindSlowestPaths[circuit, 8, TRUE]; Mint.PrintPathArray[slowNodes, circuit]; Mint.KillCircuit[circuit]}; LichenCk: PROC[h: Handle] = { PWCoreLichen.SetAutomorphismHack[TRUE]; FOR list: Cells _ h.cells, list.rest WHILE list #NIL DO IF ~HasLayout[list.first] THEN LOOP; log.PutF["\nLichen Check of %g.\n", IO.rope[CoreOps.GetCellTypeName[list.first]] ]; [] _ PWCoreLichen.CompareForTheRestOfUs[list.first, h.schDesign, 1.0] ENDLOOP}; StaticCk: PROC[h: Handle] = { FOR list: Cells _ h.cells, list.rest WHILE list #NIL DO StaticCheck[list.first] ENDLOOP}; StaticCheck: PROC[ref: Core.CellType, useLayoutIfPresent: BOOL _ TRUE] = { layout: BOOL _ useLayoutIfPresent AND HasLayout[ref]; cell: Core.CellType _ IF layout THEN PWCore.LayoutInfo[ref].extractedCT ELSE ref; log.PutF["\nStatic Check of %g %g.\n", IO.rope[CoreOps.GetCellTypeName[ref]], IO.rope[IF layout THEN "layout" ELSE "source"]]; Static.CountLeafConnections[cell, Static.CheckCount]}; ConnectCk: PROC[h: Handle] = { FOR list: Cells _ h.cells, list.rest WHILE list #NIL DO ConnectCheck[list.first] ENDLOOP}; ConnectCheck: PROC[source: Core.CellType] = { IF HasLayout[source] THEN { name: IO.ROPE _ CoreOps.GetCellTypeName[source]; obj: CD.Object _ PWCore.LayoutInfo[source].layout; ect: Core.CellType _ PWCore.LayoutInfo[source].extractedCT; log.PutF["\nCheck Routing Objects of %g.\n",IO.rope[name]]; RoutingCheck.CheckObject[obj]; log.PutF["\nCheck Connectivity of %g.\n",IO.rope[name]]; [] _ Nodeness.GetNodeness[layMode.decoration, layMode.touchProc, ect] }}; enableDRC: BOOL _ TRUE; DRCDesign: PROC[h: Handle] = { rules: IO.ROPE _ "VTI"; inst: CD.Instance; reportMsg: IO.ROPE _ NIL; hasErrors: BOOL _ TRUE; IF ~enableDRC THEN RETURN; [h.layDesign, inst] _ MakeDRCTestObject[h]; [reportMsg, hasErrors] _ DraculaOps.DRCInstance[inst, h.layDesign, rules]; IF hasErrors THEN log.PutF["*** DRC Errors\n %g\n", IO.rope[reportMsg]] ELSE log.PutF["No DRC Errors\n %g\n", IO.rope[reportMsg]]}; DRCDesignFile: PROC[file: IO.ROPE] = { design: CD.Design _ GetDesign[file]; inst: CD.Instance _ CDOps.InstList[design].first; rules: IO.ROPE _ "VTI"; reportMsg: IO.ROPE _ NIL; hasErrors: BOOL _ TRUE; [reportMsg, hasErrors] _ DraculaOps.DRCInstance[inst, design, rules]; IF hasErrors THEN log.PutF["*** DRC Errors\n %g\n", IO.rope[reportMsg]] ELSE log.PutF["No DRC Errors\n %g\n", IO.rope[reportMsg]]}; MakeDRCTestObject: PROC[h: Handle] RETURNS[design: CD.Design, inst: CD.Instance] = { TwoObjects: TYPE = RECORD[o0, o1: CD.Object, b: BOOL]; viewer: ViewerClasses.Viewer; area: REAL _ 0.0; tech: CD.Technology _ CMosB.cmosB; sep: INT _ tech.lambda*16; maxX: INT _ 0; pos: CD.Position _ [0, 0]; height: INT; insts: CD.InstanceList; object: CD.Object; objs: LIST OF CD.Object; design _ CDOps.CreateDesign[tech]; CDOps.SetMutability[design]; viewer _ CDViewer.CreateViewer[design, FALSE]; FOR list: Cells _ h.cells, list.rest WHILE list #NIL DO IF ~HasLayout[list.first] THEN LOOP; objs _ CONS[PWCore.LayoutInfo[list.first].layout, objs] ENDLOOP; DO chngd: BOOL _ FALSE; FOR list: LIST OF CD.Object _ objs, list.rest WHILE list.rest#NIL DO size1: CD.Position _ CD.InterestSize[list.first]; size2: CD.Position _ CD.InterestSize[list.rest.first]; SELECT Basics.CompareInt[ size1.x, size2.x] FROM less => LOOP; greater => [list.first, list.rest.first, chngd] _ TwoObjects[list.rest.first, list.first, TRUE]; ENDCASE => SELECT Basics.CompareInt[ size1.y, size2.y] FROM less => LOOP; greater => [list.first, list.rest.first, chngd]_TwoObjects[list.rest.first, list.first, TRUE]; ENDCASE ENDLOOP; IF ~chngd THEN EXIT ENDLOOP; FOR list: LIST OF CD.Object _ objs, list.rest WHILE list#NIL DO size1: CD.Position _ CD.InterestSize[list.first]; area _ area + (size1.x+sep) * (size1.y+sep) ENDLOOP; height _ Real.Fix[RealFns.SqRt[area]]; FOR list: LIST OF CD.Object _ objs, list.rest WHILE list#NIL DO size: CD.Position _ CD.InterestSize[list.first]; off: CD.Position _ CDBasics.SubPoints[pos, CDBasics.BaseOfRect[CD.InterestRect[list.first]]]; insts _ CONS[NEW[CD.InstanceRep _ [list.first, [off]]], insts]; pos _ [pos.x, pos.y+size.y+sep]; maxX _ MAX[maxX, size.x]; IF pos.y>height THEN {pos.x _ pos.x + maxX + sep; pos.y _ 0; maxX _ 0}; ENDLOOP; object _ PW.CreateCell[insts, , "DRCCheck"]; IF ~CDDirectory.Include[design, object, "DRCCheck"] THEN ERROR; inst _ CDOps.IncludeObject[design, object]; inst.selected _ TRUE}; <> 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]}; SelectObjectsForExtraction: PROC[design: CD.Design] = { <> IsIcon: PROC[nm: IO.ROPE] RETURNS[BOOL] = {RETURN[ (nm.Index[0, ".icon", FALSE]+5) = nm.Length[] ]}; IsSch: PROC[nm: IO.ROPE] RETURNS[BOOL] = {RETURN[ (nm.Index[0, ".sch", FALSE]+4) = nm.Length[] ]}; Root: PROC[nm: IO.ROPE] RETURNS[IO.ROPE] = {RETURN[ nm.Substr[0, nm.Index[0, "."]] ]}; iconReg: SymTab.Ref _ SymTab.Create[]; FOR list: CD.InstanceList _ CDOps.InstList[design], list.rest WHILE list#NIL DO name: IO.ROPE _ CDDirectory.Name[list.first.ob, design]; IF IsIcon[name] THEN []_SymTab.Store[iconReg, Root[name], name] ENDLOOP; FOR list: CD.InstanceList _ CDOps.InstList[design], list.rest WHILE list#NIL DO name: IO.ROPE _ CDDirectory.Name[list.first.ob, design]; list.first.selected _ IsIcon[name] OR IsSch[name] AND ~SymTab.Fetch[iconReg, Root[name]].found; IF list.first.selected THEN log.PutF["Selecting: %g\n", IO.rope[name]] ENDLOOP}; HasLayout: PROC[cell: Core.CellType] RETURNS[BOOL] = {RETURN[PWCore.GetLayoutAtom[cell]#NIL]}; <> <> <> <> <> <> <> Commander.Register["CheckDesign", CheckDesignCmdProc] END. <<>>