<> <> 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]; 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\n", [integer[d.cellTypes.Size.EN]]]; 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] = { 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["]; IF ct.bbox # fullRange2 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]; mx: Sets.MaybeValue ~ IF cct.d.ciXfm#nilBiRel THEN cct.d.ciXfm.ApplyA[ci] ELSE Sets.noMaybe; [] _ cct.d.SteppyDescribe[ci, cct, nameGen]; PrintNameAndAliases[to, cct.INames[ci]]; to.PutF[": %g", [rope[cct.d.Describe[ict, cct.d, nameGen]]] ]; IF mx.found AND ci.offset#dullInt2 THEN to.PutF["{%g %g,%g}", [rope[FormatTransform[VXfm[mx.it]]]], [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 IF first THEN first _ FALSE ELSE {to.PutRope[";"]; SS.Bp[to, width, printStep, " "]}; to.PutF["{%g,%g :", [integer[ IF a. to.PutChar[' ]; to.PutRope[VXfm[a. IF a.offsets#NIL THEN { c to.PutF[" %g,%g", [integer[a.offsets[c IF a.size2#a.basePeriod THEN to.PutF[" + %g,%g", [integer[a.offsets[c 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 a. 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.