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 =
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.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]};
Individual Operations
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};
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];
viewerViewer.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};