LichenPrintingImpl.Mesa
Last tweaked by Mike Spreitzer on November 3, 1988 3:30:29 pm PST
DIRECTORY AbSets, BasicTime, BiRels, FS, IntStuff, IO, LichenDataStructure, LichenIntBasics, LichenPrinting, Rope, SetBasics, StructuredStreams, TiogaAccess, UnparserBuffer;
LichenPrintingImpl:
CEDAR
PROGRAM
IMPORTS AbSets, BasicTime, BiRels, FS, IntStuff, IO, LichenDataStructure, LichenIntBasics, Rope, SetBasics, StructuredStreams, TiogaAccess, UnparserBuffer
EXPORTS LichenPrinting
=
BEGIN OPEN IB:LichenIntBasics, IB, LichenDataStructure, LichenPrinting, Ints:IntStuff, Sets:AbSets, SS:StructuredStreams, UB:UnparserBuffer;
printStep: INT ← 2;
printWidth: INT ← 74;
sortTops: BOOL ← TRUE;
PrintObject:
PROC [to:
IO.
STREAM, united:
BOOL,
PrintIt:
PROC] = {
SS.Bp[to, IF united THEN united ELSE lookLeft, printStep];
SS.Begin[to];
PrintIt[!UNWIND => SS.End[to]];
SS.End[to];
RETURN};
PrintRope:
PROC [to:
IO.
STREAM, united:
BOOL, rope:
ROPE] = {
SS.Bp[to, IF united THEN united ELSE lookLeft, printStep];
SS.Begin[to];
to.PutRope[rope !UNWIND => SS.End[to]];
SS.End[to];
RETURN};
PrintDesignOnFiles:
PUBLIC
PROC [d: Design, nameGen: NameGenerator ←
NIL, fnPrefix, fnSuffix:
ROPE ←
NIL, tioga:
BOOL ←
FALSE, pacify:
IO.
STREAM ←
NIL,
Filter: CellTypeFilter ←
NIL] = {
realFNPrefix: ROPE ~ IF fnPrefix#NIL THEN fnPrefix ELSE Describe[d: d, subject: d, nameGen: nameGen];
realFNSuffix: ROPE ~ IF fnSuffix#NIL THEN fnSuffix ELSE "design";
n: NAT ← 0;
order: Sets.Order ~ BiRels.MapOrder[d.ctName, leftToRight, Sets.fwd, Sets.alleq];
CtPrint:
PROC [ctv: Sets.Value]
RETURNS [
BOOL] = {
ct: CellType = NARROW[ctv.VA];
ctName: ROPE ~ ct.ACtName[];
realFileName: ROPE ~ Rope.Cat[realFNPrefix, "/", ctName.Translate[translator: BlandifyChar], ".", realFNSuffix];
ss, fs: IO.STREAM;
taw: TiogaAccess.Writer;
start: BasicTime.Pulses;
IF tioga
THEN {
taw ← TiogaAccess.Create[];
ss ← SS.Create[UB.NewInittedHandle[[output: [access[taw, printStep]], margin: printWidth]]];
}
ELSE {
fs ← FS.StreamOpen[fileName: realFileName, accessOptions: create, keep: 10];
ss ← SS.Create[UB.NewInittedHandle[[output: [stream[fs]], margin: printWidth]]];
};
IF pacify#
NIL
THEN {
pacify.PutF["%g: %g ", [integer[n ← n+1]], [rope[Describe[d, ct, d, nameGen]]]];
start ← BasicTime.GetClockPulses[]};
PrintCellType[ss, ct, nameGen];
ss.PutRope["\n"];
IF pacify#
NIL
THEN {
stop: BasicTime.Pulses ~ BasicTime.GetClockPulses[];
pacify.PutF[" %g\n", [real[BasicTime.PulsesToSeconds[stop-start]]]]};
IF tioga THEN TiogaAccess.WriteFile[taw, realFileName] ELSE IO.Close[fs];
ss.Close[];
RETURN [FALSE]};
IF pacify#
NIL
THEN {
pacify.PutF["Total: %g\nCrossed=", [integer[d.cellTypes.Size.EN]]];
d.crossedCellTypes.PrintSet[pacify];
pacify.PutRope[".\n"]};
IF d.cellTypes.Scan[CtPrint, order].found THEN ERROR;
RETURN};
BlandifyChar:
PROC [old:
CHAR]
RETURNS [new:
CHAR] ~ {
SELECT old
FROM
IN ['a .. 'z], IN ['A .. 'Z], IN ['0 .. '9], '., '- => RETURN [old];
', => RETURN ['.];
': => RETURN ['~];
ENDCASE => RETURN ['$]};
PrintDesignOnFile:
PUBLIC
PROC [d: Design, nameGen: NameGenerator ←
NIL, fileName:
ROPE ←
NIL, tioga:
BOOL ←
FALSE, pacify:
IO.
STREAM ←
NIL,
Filter: CellTypeFilter ←
NIL] = {
realFileName: ROPE = IF fileName # NIL THEN fileName ELSE Rope.Cat[Describe[d: d, subject: d, nameGen: nameGen], ".design"];
ss, fs: IO.STREAM;
taw: TiogaAccess.Writer;
IF tioga
THEN {
taw ← TiogaAccess.Create[];
ss ← SS.Create[UB.NewInittedHandle[[output: [access[taw, printStep]], margin: printWidth]]];
}
ELSE {
fs ← FS.StreamOpen[fileName: realFileName, accessOptions: create, keep: 10];
ss ← SS.Create[UB.NewInittedHandle[[output: [stream[fs]], margin: printWidth]]];
};
PrintDesignSubset[ss, d, nameGen, pacify, Filter];
IF tioga THEN TiogaAccess.WriteFile[taw, realFileName] ELSE IO.Close[fs];
ss.Close[];
RETURN};
PrintDesign:
PUBLIC
PROC [to:
IO.
STREAM, d: Design, nameGen: NameGenerator ←
NIL, pacify:
IO.
STREAM ←
NIL] = {
PrintDesignSubset[to, d, nameGen, pacify, NIL];
RETURN};
PrintDesignSubset:
PUBLIC
PROC [to:
IO.
STREAM, d: Design, nameGen: NameGenerator ←
NIL, pacify:
IO.
STREAM ←
NIL,
Filter: CellTypeFilter ←
NIL] = {
n: NAT ← 0;
order: Sets.Order ~ BiRels.MapOrder[d.ctName, leftToRight, Sets.fwd, Sets.alleq];
CTPrint:
PROC [ra:
REF
ANY] = {
ct: CellType = NARROW[ra];
Inner:
PROC = {
start: BasicTime.Pulses;
IF pacify#
NIL
THEN {
pacify.PutF["%g: %g ", [integer[n ← n+1]], [rope[Describe[d, ct, d, nameGen]]]];
start ← BasicTime.GetClockPulses[]};
PrintCellType[to, ct, nameGen];
IF pacify#
NIL
THEN {
stop: BasicTime.Pulses ~ BasicTime.GetClockPulses[];
pacify.PutF[" %g\n", [real[BasicTime.PulsesToSeconds[stop-start]]]]};
RETURN};
IF Filter=NIL OR Filter[ct] THEN PrintObject[to, TRUE, Inner];
RETURN};
IF pacify#NIL AND Filter=NIL THEN pacify.PutF["Total: %g\n", [integer[d.cellTypes.Size.EN]]];
IF NOT SS.IsAnSS[to] THEN to ← SS.Create[UB.NewInittedHandle[[output: [stream[to]], margin: printWidth]]];
to.PutF["%g: Design {", [rope[Describe[d: d, subject: d, nameGen: nameGen]]]];
IF d.scale#0.0 THEN to.PutF["linear unit = %g microns, ", [real[d.scale*1.0E6]]];
d.cellTypes.EnumA[CTPrint, order];
to.PutF["}"];
RETURN};
PrintNameAndAliases:
PROC [to:
IO.
STREAM, names: Set
--of SteppyName--, nonrelnames: Set ← nilSet] ~ {
first, second: BOOL ← TRUE;
prefix: ROPE ← NIL;
PerName:
PROC [val: Sets.Value] ~ {
name: SteppyName ~ VSn[val];
IF first
THEN first ←
FALSE
ELSE {
IF second THEN {to.PutRope["(a.k.a."]; second ← FALSE} ELSE to.PutRope[","];
SS.Bp[to, width, printStep, " "];
};
to.PutRope[prefix];
to.PutRope[UnparseSteppyName[name]];
RETURN};
names.Enumerate[PerName];
IF nonrelnames#nilSet
THEN {
prefix ← "/";
nonrelnames.Enumerate[PerName]};
IF NOT second THEN to.PutRope[")"];
RETURN};
PrintCellType:
PUBLIC
PROC [to:
IO.
STREAM, ct: CellType, nameGen: NameGenerator ←
NIL] = {
CrossPrint: PROC ~ {to.PutRope[IF ct.d.crossedCellTypes.HasMemA[ct] THEN "crossed" ELSE "uncrossed"]};
BBPrint: PROC ~ {to.PutF["bbox: [%g,%g,%g,%g]", [integer[ct.bbox[X].min]], [integer[ct.bbox[Y].min]], [integer[ct.bbox[X].maxPlusOne]], [integer[ct.bbox[Y].maxPlusOne]]]};
PortPrint:
PROC = {
tops: Set ~ ct.TopParts[p];
sep: ROPE ← NIL;
PrintAPort:
PROC [pv: Sets.Value]
RETURNS [
BOOL] ~ {
p: Port ~ NARROW[pv.VA];
PPrint: PROC ~ {PrintPW[to, ct, p, p, NIL, nameGen]};
to.PutRope[sep]; PrintObject[to, FALSE, PPrint];
sep ← ", "; RETURN [FALSE]};
to.PutRope["ports: ["];
IF tops.Scan[PrintAPort, IF sortTops THEN ct.nameOrder[p] ELSE Sets.alleq].found THEN ERROR;
to.PutRope["]"];
RETURN};
IWPrint:
PROC = {
tops: Set ~ ct.TopParts[w];
sep: ROPE ← NIL;
PrintAWire:
PROC [wv: Sets.Value]
RETURNS [
BOOL] ~ {
w: Wire ~ NARROW[wv.VA];
WPrint: PROC ~ {PrintPW[to, ct, w, w, NIL, nameGen]};
to.PutRope[sep]; PrintObject[to, FALSE, WPrint];
sep ← ", "; RETURN [FALSE]};
to.PutRope["internal wires: ["];
IF tops.Scan[PrintAWire, IF sortTops THEN ct.nameOrder[w] ELSE Sets.alleq].found THEN ERROR;
to.PutRope["]"];
RETURN};
CIPrint:
PROC = {
to.PutF["connection sites: "];
PrintCells[to, ct, ct.Subcells, ct, nameGen];
RETURN};
AyPrint:
PROC = {
to.PutRope["asArray: "];
PrintArray[to, ct, nameGen]
};
IF NOT SS.IsAnSS[to] THEN to ← SS.Create[UB.NewInittedHandle[[output: [stream[to]], margin: printWidth]]];
to.PutRope[Describe[ct.d, ct, ct.d, nameGen]];
to.PutRope[": CellType["];
PrintObject[to, FALSE, CrossPrint];
to.PutRope[", "];
IF ct.d.physd THEN {PrintObject[to, FALSE, BBPrint]; to.PutRope[", "]};
PrintObject[to, TRUE, PortPrint];
IF ct.asu #
NIL
THEN {
to.PutRope[", "]; PrintObject[to, TRUE, IWPrint];
to.PutRope[", "]; PrintObject[to, TRUE, CIPrint];
};
IF ct.asArray #
NIL
THEN {
to.PutRope[", "]; PrintObject[to, TRUE, AyPrint];
};
to.PutRope["]"];
};
PrintPW:
PROC [to:
IO.
STREAM, ct: CellType, class: PWClass, pw:
PW, parent:
PW ←
NIL, nameGen: NameGenerator ←
NIL] ~ {
[] ← ct.d.SteppyDescribe[pw, IF parent#NIL THEN parent ELSE ct, nameGen];
{fullNames: Set ~ ct.fullName[class].MappingA[pw];
IF parent#
NIL
THEN {
relNames: Set ~ RelativeNames[ct, class, parent, pw];
reldNames: Set ~ SNsCat[ct.fullName[class].MappingA[parent], relNames];
nonRelNames: Set ~ fullNames.Difference[reldNames];
PrintNameAndAliases[to, relNames, nonRelNames];
to ← to}
ELSE PrintNameAndAliases[to, fullNames];
IF ct.d.Atomic[pw] THEN RETURN;
{shape: LOI ~ Shape[ct, class, pw];
IF shape#
NIL
THEN {
IF shape.rest=NIL THEN ERROR;
FOR dims:
LOI ← shape, dims.rest
WHILE dims.rest#
NIL
DO
to.PutF["*%g", [integer[dims.first]]];
ENDLOOP;
RETURN};
{kids: Seq ~ BiRels.DeRef[ct.d.sub.ApplyA[pw].MA];
first: BOOL ← TRUE;
to.PutRope["["];
FOR i:
INT
IN [0 .. kids.Size.
EN)
DO
kid: PW ~ kids.ApplyI[i].MA;
PWPrint: PROC ~ {PrintPW[to, ct, class, kid, pw, nameGen]};
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, FALSE, PWPrint];
ENDLOOP;
to.PutRope["]"];
RETURN}}}};
listOne: LOI ~ LIST[1];
Shape:
PROC [ct: CellType, class: PWClass, pw:
PW]
RETURNS [
LOI] ~ {
IF ct.d.Atomic[pw] THEN RETURN [listOne];
{kids: Seq ~ BiRels.DeRef[ct.d.sub.ApplyA[pw].MA];
width: LNAT ~ kids.Size.EN;
subShape: LOI ← NIL;
FOR i:
INT
IN [0 .. width)
DO
kid: PW ~ kids.ApplyI[i].MA;
thissub: LOI;
AcceptIndex:
PROC [sn: SteppyName]
RETURNS [
BOOL] ~ {
IF sn.grade.nonsubs#0 OR sn.grade.subs#1 THEN RETURN [FALSE];
IF NARROW[sn.steps.first, REF INT]^ # i THEN RETURN [FALSE];
RETURN [TRUE]};
IF NOT ct.ScanRelativeNames[class, pw, kid, AcceptIndex].found THEN RETURN [NIL];
thissub ← Shape[ct, class, kid];
IF thissub=NIL THEN RETURN [NIL];
IF subShape=NIL THEN subShape ← thissub ELSE IF NOT LoiEqual[subShape, thissub] THEN RETURN [NIL];
ENDLOOP;
RETURN [CONS[width, subShape]]}};
LoiEqual:
PROC [l1, l2:
LOI]
RETURNS [
BOOL] ~ {
WHILE l1#l2
DO
IF l1=NIL OR l2=NIL OR l1.first#l2.first THEN RETURN [FALSE];
l1 ← l1.rest;
l2 ← l2.rest;
ENDLOOP;
RETURN [TRUE]};
PrintCells:
PUBLIC
PROC [to:
IO.
STREAM, cct: CellType, set: Set
--OF Cell--, and: Cell ←
NIL, nameGen: NameGenerator ←
NIL] = {
order: Sets.Order ~ cct.nameOrder[i];
first: BOOL ← TRUE;
PrintIt:
PROC [cell: Cell] = {
IPrint: PROC = {PrintCell[to, cct, cell, nameGen]};
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, TRUE, IPrint];
};
to.PutRope["["];
set.EnumA[PrintIt, order];
IF and#NIL THEN PrintIt[and];
to.PutRope["]"];
};
PrintCell:
PUBLIC
PROC [to:
IO.
STREAM, cct: CellType, cell: Cell, nameGen: NameGenerator ←
NIL] = {
WITH cell
SELECT
FROM
ct: CellType => {
IF ct # cct THEN ERROR;
to.PutRope["exports"];
PrintForPorts[to, ct.asu.exports, cct.d.sub, cct.d.parent, ct, BiRels.EnumSeqOfSet[ct.TopParts[p], IF sortTops THEN ct.nameOrder[p] ELSE Sets.alleq], ct, cct.d.eSpace, nameGen];
RETURN};
ci: CellInstance => {
ict: CellType ~ cct.d.CiT[ci];
xfm: Transform ~ IF cct.d.physd THEN VXfm[cct.d.ciXfm.ApplyA[ci].Val] ELSE [];
[] ← cct.d.SteppyDescribe[ci, cct, nameGen];
PrintNameAndAliases[to, cct.INames[ci]];
to.PutF[": %g", [rope[cct.d.Describe[ict, cct.d, nameGen]]] ];
IF cct.d.physd THEN to.PutF["{%g %g,%g}", [rope[FormatTransform[xfm]]], [integer[ci.offset[X]]], [integer[ci.offset[Y]]]];
PrintForPorts[to, ci.conns, cct.d.sub, cct.d.parent, ict, BiRels.EnumSeqOfSet[ict.TopParts[p], IF sortTops THEN ict.nameOrder[p] ELSE Sets.alleq], ict, cct.d.eSpace, nameGen];
RETURN};
ENDCASE => ERROR;
};
PrintForPorts:
PROC [to:
IO.
STREAM, conns, sub, parent: BiRel, pct: CellType, ports: Seq
--of Port--, rel:
REF
ANY, wSpace: Sets.Space, nameGen: NameGenerator] = {
first: BOOL ← TRUE;
PrintForPort:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
p: Port ~ NARROW[pair[right].VA];
CPrint:
PROC ~ {
wmv: Sets.MaybeValue ~ conns.ApplyA[p];
to.PutRope[pct.d.Describe[p, rel, nameGen]];
to.PutRope[": "];
IF wmv.found THEN {to.PutRope[wSpace.SFormat[wmv.it]]; RETURN};
{pkids: Seq--of Port-- ~ BiRels.DeRef[pct.d.sub.ApplyA[p].MDA];
IF pkids=nilBiRel THEN {to.PutRope["??"]; RETURN};
{wkids: Seq--of Wire-- ~ pkids.Compose[conns];
nwkids: NATURAL ~ wkids.Size.EN;
npkids: NATURAL ~ pkids.Size.EN;
IF nwkids#npkids THEN GOTO NotEasy;
{ws: Set--of Wire-- ~ wkids.SetOn[right];
IF ws.Size=Ints.one THEN {to.PutF["%g*%g", [rope[wSpace.SFormat[ws.TheElt]]], [integer[pkids.Size.EN]]]; RETURN};
{wparents: Set--of Wire-- ~ parent.Image[ws];
IF wparents.Size#Ints.one THEN GOTO NotEasy;
{wparent: Sets.Value ~ wparents.TheElt;
allwkids: Seq--of Wire-- ~ BiRels.VB[sub.Apply[wparent].Val];
mi: Sets.MaybeValue ~ allwkids.Index[wkids];
IF NOT mi.found THEN GOTO NotEasy;
{base: NATURAL ~ mi.it.VI;
to.PutRope[wSpace.SFormat[wparent]];
IF base#0 OR allwkids.Size.EN#npkids THEN to.PutF["[%g..%g]", [integer[base]], [integer[base+npkids-1]] ];
RETURN}}}};
EXITS NotEasy => NULL};
PrintForPorts[to, conns, sub, parent, pct, pkids, p, wSpace, nameGen];
RETURN}};
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, FALSE, CPrint];
RETURN [FALSE]};
to.PutRope["["];
IF ports.Scan[PrintForPort].found THEN ERROR;
to.PutRope["]"];
RETURN};
printStatRep: BOOL ← TRUE;
printDumbRep: BOOL ← FALSE;
printStatExports: BOOL ← TRUE;
PrintArray:
PUBLIC
PROC [to:
IO.
STREAM, act: CellType, nameGen: NameGenerator ←
NIL] = {
a: Array = act.asArray;
ect: CellType ~ act.EltType[];
BasePrint:
PROC = {
to.PutF["base period = [%g, %g]", [integer[a.basePeriod[X]]], [integer[a.basePeriod[Y]]]]};
StatPrint:
PROC = {
to.PutRope["static graph = ["];
PrintStatRep[to, act, nameGen];
to.PutRope["]"]};
PhysPrint:
PROC ~ {
first: BOOL ← TRUE;
to.PutRope["transforms = ["];
FOR
f
x: Int
IN [0 .. a.basePeriod[X])
DO
FOR
f
y: Int
IN [0 .. a.basePeriod[Y])
DO
f: Int2 ~ [fx, fy];
cf: NATURAL ~ ComposePhase[a, f];
IF first THEN first ← FALSE ELSE {to.PutRope[";"]; SS.Bp[to, width, printStep, " "]};
to.PutF["{%g,%g :", [integer[fx]], [integer[fy]]];
to.PutChar[' ];
to.PutRope[VXfm[a.fXfm.Apply[I2V[f]].Val].FormatTransform];
to.PutF[" %g,%g", [integer[a.offsets[cf].o0[X]]], [integer[a.offsets[cf].o0[Y]]] ];
IF a.size2#a.basePeriod THEN to.PutF[" + %g,%g", [integer[a.offsets[cf].o1[X]]], [integer[a.offsets[cf].o1[Y]]] ];
to.PutRope["}"];
ENDLOOP ENDLOOP;
to.PutRope["]"]};
StatExpPrint:
PROC = {
to.PutRope["static exports = "];
PrintStatExp[to, act, nameGen];
RETURN};
to.PutF["{%g BY %g OF %g, ",
[integer[a.size2[X]]], [integer[a.size2[Y]]],
[rope[act.d.Describe[ect, act.d, nameGen]]]
];
PrintObject[to, FALSE, BasePrint];
IF act.d.physd
THEN {
to.PutRope[", "];
PrintObject[to, TRUE, PhysPrint]};
IF printStatRep
THEN {
to.PutRope[", "];
PrintObject[to, TRUE, StatPrint];
};
IF printStatExports
THEN {
to.PutRope[", "];
PrintObject[to, TRUE, StatExpPrint];
};
IF printDumbRep THEN ERROR nyet;
to.PutRope["}"];
};
PrintStatRep:
PROC [to:
IO.
STREAM, act: CellType, nameGen: NameGenerator] ~ {
a: Array = act.asArray;
ect: CellType ~ act.EltType[];
firstEdge: BOOL ← TRUE;
EnsureNamed:
PROC [part: Part] ~ {
[] ← act.d.SteppyDescribe[part, ect, nameGen];
RETURN};
PrintEdge:
PROC [val: Sets.Value] ~ {
IF firstEdge THEN firstEdge ← FALSE ELSE to.PutRope[", "];
PrintRope[to, TRUE, a.statrep.edgeSpace.SFormat[val]];
RETURN};
ect.EnumCTParts[p, TRUE, TRUE, EnsureNamed];
a.statrep.edges.Enumerate[PrintEdge, a.statrep.edgeNameOrder];
RETURN};
PrintStatExp:
PROC [to:
IO.
STREAM, act: CellType, nameGen: NameGenerator] ~ {
a: Array = act.asArray;
ect: CellType ~ act.EltType[];
first: BOOL ← TRUE;
EnsureNamed:
PROC [part: Part] ~ {
[] ← act.d.SteppyDescribe[part, ect, nameGen];
RETURN};
IF NOT printStatRep THEN ect.EnumCTParts[p, TRUE, TRUE, EnsureNamed];
PrintForPorts[to, a.dumrep.apToWire, a.dumrep.dwSub, a.dumrep.dwParent, act, BiRels.EnumSeqOfSet[act.TopParts[p], IF sortTops THEN act.nameOrder[p] ELSE Sets.alleq], act, a.dumrep.dwSpace, nameGen];
RETURN};
IsArray: PROC [ct: CellType] RETURNS [pass: BOOL] = {pass ← ct.asArray # NIL};
Is1D:
PROC [ct: CellType]
RETURNS [
BOOL]
~ {RETURN [ct.asArray#NIL AND (ct.asArray.size2[X]=1 OR ct.asArray.size2[Y]=1)]};
Is2D:
PROC [ct: CellType]
RETURNS [
BOOL]
~ {RETURN [ct.asArray#NIL AND ct.asArray.size2[X]#1 AND ct.asArray.size2[Y]#1]};
PrintArrays:
PROC [to:
IO.
STREAM, d: Design, nameGen: NameGenerator ←
NIL, pacify:
IO.
STREAM ←
NIL] = {
PrintDesignSubset[to, d, nameGen, pacify, IsArray];
};
END.