<> <> <> 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, RefTab, Rope, RosemaryUser, RoutingCheck, Sinix, SinixOps, Sisyph, Static, SymTab, TerminalIO, ViewerClasses, ViewerOps, WriteCapa; 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, RefTab, Rope, RosemaryUser, RoutingCheck, SinixOps, Sisyph, Static, SymTab, TerminalIO, ViewerOps, WriteCapa = 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, fromFile: BOOL _ FALSE, lichen: BOOL _ TRUE, static: BOOL _ TRUE, mint: BOOL _ TRUE, rose: BOOL _ TRUE, conn: BOOL _ TRUE, drc: BOOL _ TRUE ]; Cells: TYPE = LIST OF Core.CellType; log: IO.STREAM _ TerminalIO.TOS[]; layMode: Sinix.Mode = PWCore.extractMode; schMode: Sinix.Mode = Sisyph.mode; mintSchNodeCapa: REAL _ 0.5; doc: IO.ROPE _ "CheckDesign designName -f read cell from file (designName used as deviceName) -l skip lichen check -s skip static check -m skip mint check -r skip rose simulation check -c skip connectivity check -d skip drc check "; <> 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[]; designPrintNm: IO.ROPE; cellPrintNm: IO.ROPE; IF h=NIL THEN {cmd.out.PutRope[doc]; RETURN[$Failure]}; designPrintNm _ IF h.designNm=NIL THEN "(from file)" ELSE h.designNm; 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[designPrintNm]]]; Log[IO.PutFR[" Cell: %g\n", IO.rope[cellPrintNm]]]; Log[IO.PutFR[" start %g\n", IO.time[]]]; IF ~h.fromFile THEN {Log[" Extract Src ... "]; ExtractSrc [h]; LogDone[]}; IF h.fromFile THEN {Log[" Read Src ... "]; ReadSrc [h]; LogDone[]}; IF TRUE THEN {Log[" Gen Lay ... "]; GenLayout [h]; LogDone[]}; IF TRUE THEN {Log[" Extract Lay ... "]; ExtractLay [h]; LogDone[]}; IF h.lichen THEN {Log[" Lichen Ck ... "]; LichenCk [h]; LogDone[]}; IF h.static THEN {Log[" Static Ck ... "]; StaticCk [h]; LogDone[]}; IF h.mint THEN {Log[" Mint Ck ... "]; MintCk [h]; LogDone[]}; IF h.rose THEN {Log[" Rose Ck ... "]; SimCk [h]; LogDone[]}; IF h.conn THEN {Log[" Conn Ck ... "]; ConnectCk [h]; LogDone[]}; IF h.drc THEN {Log[" DRC Ck ... "]; DRCDesign [h]; LogDone[]}; CedarProcess.SetPriority[initialPriority]}; <> InitHandle: PROC[cmd: Commander.Handle] RETURNS[h: Handle] = { list: LIST OF IO.ROPE _ CommandTool.ParseToList[cmd].list; schNm: IO.ROPE _ NIL; designNm: IO.ROPE _ NIL; h _ NEW[HandleRec _ []]; FOR list _ list, list.rest WHILE list#NIL DO SELECT list.first.Fetch[] FROM '- => SELECT list.first.Fetch[1] FROM 'f, 'F => {h.lichen _ FALSE; h.rose _ FALSE; h.fromFile _ TRUE}; 'l, 'L => h.lichen _ FALSE; 's, 'S => h.static _ FALSE; 'm,'M => h.mint _ FALSE; 'r, 'R => h.rose _ FALSE; 'c, 'C => h.conn _ FALSE; 'd, 'D => h.drc _ FALSE; ENDCASE => {cmd.out.PutRope["\nUnknown switch\n"]; RETURN[NIL]}; ENDCASE => { IF h.designNm=NIL THEN h.designNm _ list.first ELSE IF schNm=NIL THEN schNm _ list.first ELSE {cmd.out.PutRope["\nMore than 2 arguments\n"]; RETURN[NIL]}}; ENDLOOP; IF h.fromFile THEN {h.schNm _ h.designNm; h.designNm _ NIL; RETURN[h]}; 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]; IF schNm#NIL THEN { h.schNm _ schNm; 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} }; ReadSrc: PROC[h: Handle] = {ct: Core.CellType _ PWCore.Retrieve[h.schNm]; h.cells _ LIST[ct]}; 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[ct.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 { Mint.SetNode[node, TRUE]; log.PutF["Mint Clock: %g\n", IO.rope[hiNm]]; list _ CONS[node, list]}; IF (node _ GetNode[loNm])#NIL THEN { Mint.SetNode[node, FALSE]; log.PutF["Mint Clock: %g\n", IO.rope[loNm]]; list _ CONS[node, list]} }}; InitCT: PROC RETURNS[Core.CellType] = { ct: Core.CellType _ IF layout THEN PWCore.LayoutInfo[cell].extractedCT ELSE cell; IF layout THEN { <> <> WriteCapa.WriteWireCapa[ct, $cmosB]}; RETURN[ct]}; name: IO.ROPE _ CoreOps.GetCellTypeName[cell]; layout: BOOL _ useLayoutIfPresent AND HasLayout[cell]; ct: Core.CellType _ InitCT[]; defaultCapa: REAL _ IF layout THEN 0.0 ELSE mintSchNodeCapa; circuit: Mint.Circuit _ Mint.CreateCircuit[ct, layout, defaultCapa]; 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; log.PutF["\nMint Check of %g %g.\n", IO.rope[CoreOps.GetCellTypeName[cell]], IO.rope[IF layout THEN "layout" ELSE "source"]]; IF vddNode=NIL THEN {log.PutF["*** Cell: %g does not have a Vdd connection.\n", IO.rope[name]]; RETURN}; IF gndNode=NIL THEN {log.PutF["*** Cell: %g does not have a Gnd 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]; IF h.layDesign=NIL THEN {log.PutRope["No layout to DRC\n"]; RETURN}; [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; IF objs=NIL THEN RETURN[NIL, NIL]; 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}; <> MarkMintOneWayTransistors: PROC[cell: Core.CellType] = { Mark: PROC[ct: Core.CellType] = { IF ~RefTab.Fetch[tab, ct].found THEN { WITH ct.data SELECT FROM sct: Core.CellType => {Mark[sct] }; trans: CoreClasses.Transistor => { }; seq: CoreClasses.SequenceCellType => {Mark[seq.base]}; rct: CoreClasses.RecordCellType => { cnt: INT _ 0; FOR in: NAT IN [0..rct.size) DO nm: IO.ROPE _ CoreOps.GetCellTypeName[rct[in].type]; IF nm.Equal["MintOneWay"] THEN { cnt _ cnt+1; CoreProperties.PutCellInstanceProp[rct[in], $MintOneWay, $TRUE]} ELSE Mark[rct[in].type] ENDLOOP; count _ count + cnt; IF cnt > 0 THEN log.PutF["%g has %g Mint OneWay transistors\n", IO.rope[CoreOps.GetCellTypeName[ct]], IO.int[cnt]]}; ENDCASE; []_RefTab.Store[tab, ct, ct]}}; tab: RefTab.Ref _ RefTab.Create[]; count: INT _ 0; log.PutRope["\n"]; Mark[cell]; log.PutF["%g Mint OneWay transistors were found.\n", IO.int[count]]; RefTab.Erase[tab]}; 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. <<>>