CheckDesign.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Don Curry May 9, 1988 1:15:41 pm PDT
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
Types
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 <optional sch/icon name>\n";
CheckDesign Command Proc
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.PriorityCedarProcess.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]};
Individual Operations
InitHandle: PROC[cmd: Commander.Handle] RETURNS[h: Handle] = {
argv:  CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
schNm: IO.ROPENIL;
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: BOOLTRUE] = {
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: BOOLTRUE] = {
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: BOOLTRUE;
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: BOOLFALSE;
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};
Utilities
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�Viewer.CreateViewer[design, FALSE];
ViewerOps.CloseViewer[viewer]};
SelectObjectsForExtraction: PROC[design: CD.Design] = {
All icons and all schematics (which don't have icons with the same name)
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]};
SelectObjectsForExtraction: PROC[design: CD.Design, marked: RefTab.Ref, key: IO.ROPE] = {
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 ←
name.Find[key, 0, FALSE]#-1 AND
name.Find[key, 0, FALSE] + key.Length[] = name.Length ENDLOOP};
Runtime
Commander.Register["CheckDesign", CheckDesignCmdProc]
END.