CheckDesign.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Don Curry September 8, 1988 8:12:45 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, 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
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,
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 <optional sch/icon name>
-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
";
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[];
designPrintNm: IO.ROPE;
cellPrintNm:  IO.ROPE;
IF h=NIL THEN {cmd.out.PutRope[doc]; RETURN[$Failure]};
designPrintNm ← IF h.designNm=NILTHEN "(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]};
Individual Operations
InitHandle: PROC[cmd: Commander.Handle] RETURNS[h: Handle] = {
list:   LIST OF IO.ROPE ← CommandTool.ParseToList[cmd].list;
schNm:  IO.ROPENIL;
designNm: IO.ROPENIL;
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.roseFALSE; 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
ELSEIF 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: BOOLTRUE] = {
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 {
MarkMintOneWayTransistors[ct]; this doen't work
The transistor celltype (and therefore the name) gets shared
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: 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];
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: 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
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�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.