DIRECTORY Ascii, BasicTime, CD, CDBasics, CDCells, CDCleanUp, CDCommandOps, CDDebug, CDDirectory, CDGenerate, CDInstances, CDIO, CDOps, CDProperties, CDSequencer, CDValue, GList, HashTable, IO, PW, PWObjects, Rope, RopeList, TerminalIO, ViewerClasses; PWImpl: CEDAR PROGRAM IMPORTS Ascii, BasicTime, CD, CDBasics, CDCells, CDCleanUp, CDCommandOps, CDDebug, CDDirectory, CDGenerate, CDIO, CDInstances, CDOps, CDProperties, CDSequencer, CDValue, GList, HashTable, IO, PW, PWObjects, Rope, RopeList, TerminalIO EXPORTS PW = BEGIN OPEN PW; AbutProblem: PUBLIC SIGNAL [what: ROPE, isX: BOOL, ob1, ob2: Object] = CODE; Reverse: PUBLIC PROC [objects: Objects] RETURNS [result: Objects _ NIL] = { result _ NARROW [GList.Reverse[objects]]; }; CleanAndCheck: PROC [objects: Objects, isX: BOOL] RETURNS [newObjectsj: Objects _ NIL] = BEGIN size, prSize: INT _ -1; prObj, obj: Object; IF objects=NIL THEN RETURN[NIL]; -- the list was NIL WHILE objects#NIL DO obj _ objects.first; IF obj=NIL THEN {objects _ objects.rest; LOOP}; -- skip NIL objects size _ IF isX THEN CD.InterestSize[obj].y ELSE CD.InterestSize[obj].x; -- obj is garanteed to be non-NIL newObjectsj _ CONS [obj, newObjectsj]; -- build clean list (reversed) IF prSize<0 THEN {prSize _ size; prObj _ obj; objects _ objects.rest; LOOP}; -- first time IF prSize#size THEN AbutProblem["These two objects do not match\n", isX, prObj, obj]; prSize _ size; prObj _ obj; objects _ objects.rest; ENDLOOP; newObjectsj _ Reverse[newObjectsj]; END; AbutX: PUBLIC PROC [t1,t2,t3,t4,t5,t6: Object _ NIL] RETURNS [obj: Object] = {objects: Objects _ NIL; RETURN [AbutListX[LIST[t1,t2,t3,t4,t5,t6]]]}; AbutY: PUBLIC PROC [t1,t2,t3,t4,t5,t6: Object _ NIL] RETURNS [obj: Object] = { objects: Objects _ NIL; RETURN [AbutListY[LIST[t1,t2,t3,t4,t5,t6]]]; }; AbutListX: PUBLIC PROC [objects: Objects] RETURNS [obj: Object] = { objects _ CleanAndCheck[objects, TRUE]; obj _ IF objects=NIL THEN NIL ELSE PWObjects.CreateNewAbutX[objects]; }; AbutListY: PUBLIC PROC [objects: Objects] RETURNS [obj: Object] = { objects _ CleanAndCheck[objects, FALSE]; obj _ IF objects=NIL THEN NIL ELSE PWObjects.CreateNewAbutY[objects]; }; MapFunctionX: PUBLIC PROC [function: XYFunction, lx: INT _ 0, ux: INT] RETURNS [new: Object] = BEGIN row: Objects _ NIL; IF lx>=ux THEN RETURN[NIL]; FOR x: INT DECREASING IN [lx .. ux) DO row _ CONS [function[x, 0], row]; ENDLOOP; RETURN [AbutListX[row]]; END; MapFunctionY: PUBLIC PROC [function: XYFunction, ly: INT _ 0, uy: INT] RETURNS [new: Object] = BEGIN row: Objects _ NIL; IF ly>=uy THEN RETURN[NIL]; FOR y: INT DECREASING IN [ly .. uy) DO row _ CONS [function[0, y], row]; ENDLOOP; RETURN [AbutListY[row]]; END; MapFunction: PUBLIC PROC [function: XYFunction, lx: INT _ 0, ux: INT, ly: INT _ 0, uy: INT] RETURNS [new: Object]= BEGIN rows: Objects _ NIL; IF lx>=ux OR ly>=uy THEN RETURN[NIL]; FOR y: INT DECREASING IN [ly .. uy) DO row: Objects _ NIL; FOR x: INT DECREASING IN [lx .. ux) DO row _ CONS [function[x, y], row]; ENDLOOP; rows _ CONS [AbutListX[row], rows]; ENDLOOP; RETURN [AbutListY[rows]]; END; ArrayX: PUBLIC PROC [ob: Object, nx: INT _ 1] RETURNS [new: Object] = BEGIN row: LIST OF Object _ NIL; IF nx=0 OR ob=NIL THEN RETURN[NIL]; FOR x: INT IN [0 .. nx) DO row _ CONS [ob, row]; ENDLOOP; RETURN [AbutListX[row]]; END; ArrayY: PUBLIC PROC [ob: Object, ny: INT _ 1] RETURNS [new: Object] = BEGIN row: LIST OF Object _ NIL; IF ny=0 OR ob=NIL THEN RETURN[NIL]; FOR x: INT IN [0 .. ny) DO row _ CONS [ob, row]; ENDLOOP; RETURN [AbutListY[row]]; END; Array: PUBLIC PROC [ob: Object, nx,ny: INT _ 1] RETURNS [new: Object] = {new _ ArrayY[ArrayX[ob, nx], ny];}; MapRectProc: TYPE = PROC [rect: CD.Rect] RETURNS [CD.Rect]; ChangeOrientation: PUBLIC PROC [obj: CD.Object, orientation: CD.Orientation] RETURNS [cell: CD.Object] = BEGIN cell _ CreateEmptyCell[]; [] _ IncludeInCell[cell: cell, obj: obj, orientation: orientation]; RepositionCell[cell]; END; Flatten: PUBLIC PROC [cell: Object] RETURNS [new: Object] = { TopEnumerate: CDCells.InstEnumerator = { ob: Object _ Flatten[inst.ob]; IF NOT CDCells.IsCell[ob] OR CDProperties.GetObjectProp[ob, $DontFlatten]#NIL THEN instances _ CONS [CDInstances.NewInst[ob, inst.trans, CDProperties.DCopyProps[inst.properties]], instances] ELSE { trans: CD.Transformation _ inst.trans; InsideEnumerate: CDCells.InstEnumerator = { instances _ CONS [CDInstances.Composed[inst, trans], instances]; }; [] _ CDCells.EnumerateInstances[ob, InsideEnumerate]; }; }; instances: InstanceList _ NIL; IF CDProperties.GetObjectProp[cell, $DontFlatten]#NIL THEN RETURN [cell]; IF NOT CDCells.IsCell[cell] THEN { new _ CDDirectory.Expand[cell, NIL, NIL].new; RETURN [IF new=NIL THEN cell ELSE Flatten[new]]; }; [] _ CDCells.EnumerateInstances[cell, TopEnumerate]; new _ PWObjects.CreateCell[instances: instances, ir: CD.InterestRect[cell], properties: cell.properties]; }; Get: PUBLIC PROC [design: Design, name: ROPE] RETURNS [ob: Object] = { IF design=NIL THEN ERROR; ob _ CDDirectory.Fetch[design, name].object; IF ob=NIL THEN {TerminalIO.PutF["Object %g not found in the design.\n", IO.rope[name]]; ERROR}; }; OpenDesign: PUBLIC PROC [fileName: ROPE] RETURNS [design: CD.Design] = BEGIN design _ CDIO.ReadDesign[fileName, NIL, CDIO.GetWorkingDirectory[]]; CDValue.Store[design, $KeepObjects, $KeepObjects]; -- to avoid finalization END; Register: PUBLIC PROC [userProc: UserProc, name: ROPE] = { TerminalIO.PutF["Generator program %g %g.\n", IO.rope[name], IO.rope[ IF CDGenerate.Register[context: CDGenerate.AssertContext["PatchWork"], key: name, generator: userProc, cache: FALSE] THEN "recorded" ELSE "overwritten"]]; }; sharedAbutXCache: HashTable.Table; -- Object -> HashTable(Object -> Object) sharedAbutYCache: HashTable.Table; -- Object -> HashTable(Object -> Object) SharedAbutX: PUBLIC PROC [t1, t2: Object _ NIL] RETURNS [obj: Object] = { subTable: HashTable.Table _ NARROW [HashTable.Fetch[sharedAbutXCache, t1].value]; IF subTable=NIL THEN {subTable _ HashTable.Create[2]; [] _ HashTable.Store[sharedAbutXCache, t1, subTable]}; obj _ NARROW [HashTable.Fetch[subTable, t2].value]; IF obj#NIL THEN RETURN; obj _ AbutX[t1, t2]; [] _ HashTable.Store[subTable, t2, obj]; }; SharedAbutY: PUBLIC PROC [t1, t2: Object _ NIL] RETURNS [obj: Object] = { subTable: HashTable.Table _ NARROW [HashTable.Fetch[sharedAbutYCache, t1].value]; IF subTable=NIL THEN {subTable _ HashTable.Create[2]; [] _ HashTable.Store[sharedAbutYCache, t1, subTable]}; obj _ NARROW [HashTable.Fetch[subTable, t2].value]; IF obj#NIL THEN RETURN; obj _ AbutY[t1, t2]; [] _ HashTable.Store[subTable, t2, obj]; }; SharedAbutListX: PUBLIC PROC [objects: Objects] RETURNS [obj: Object] = { revList: Objects _ NIL; IF objects=NIL THEN RETURN [NIL]; IF objects.rest=NIL THEN RETURN [objects.first]; WHILE objects#NIL AND objects.rest#NIL DO revList _ CONS [SharedAbutX[objects.first, objects.rest.first], revList]; objects _ objects.rest.rest; ENDLOOP; IF objects#NIL THEN revList _ CONS [objects.first, revList]; obj _ SharedAbutListX[Reverse[revList]]; }; SharedAbutListY: PUBLIC PROC [objects: Objects] RETURNS [obj: Object] = { revList: Objects _ NIL; IF objects=NIL THEN RETURN [NIL]; IF objects.rest=NIL THEN RETURN [objects.first]; WHILE objects#NIL AND objects.rest#NIL DO revList _ CONS [SharedAbutY[objects.first, objects.rest.first], revList]; objects _ objects.rest.rest; ENDLOOP; IF objects#NIL THEN revList _ CONS [objects.first, revList]; obj _ SharedAbutListY[Reverse[revList]]; }; FlushSharedCache: PUBLIC PROC = { sharedAbutXCache _ HashTable.Create[2]; sharedAbutYCache _ HashTable.Create[2]; }; AppendProps: PUBLIC PROC [newObj, obj: CD.Object] = { FOR l: CDProperties.PropList _ obj.properties, l.rest WHILE l#NIL DO IF ISTYPE[l.first.key, ATOM] AND CDProperties.GetObjectProp[newObj, l.first.key]=NIL THEN { p: CDProperties.PropertyProcs = CDProperties.FetchProcs[l.first.key]; IF p#NIL AND p.makeCopy#NIL THEN CDProperties.PutObjectProp[ newObj, l.first.key, p.makeCopy[l.first.key, l.first.val]]; }; ENDLOOP; }; Draw: PUBLIC PROC [obj: CD.Object, technologyName: ATOM _ NIL] RETURNS [design: CD.Design] = { design _ CDDebug.Draw[obj, IF technologyName=NIL THEN $cmosB ELSE technologyName].dummyDesign; }; PowersOfTwo: ARRAY [0 .. 33] OF INT = [ 1B, 2B, 4B, 1B1, 2B1, 4B1, 1B2, 2B2, 4B2, 1B3, 2B3, 4B3, 1B4, 2B4, 4B4, 1B5, 2B5, 4B5, 1B6, 2B6, 4B6, 1B7, 2B7, 4B7, 1B8, 2B8, 4B8, 1B8, 2B8, 4B8, 1B9, 2B9, 4B9, 1B10]; ODD: PUBLIC PROC [i: INT] RETURNS [BOOL] = {RETURN [(i MOD 2 # 0)]}; EVEN: PUBLIC PROC [i: INT] RETURNS [BOOL] = {RETURN [(i MOD 2 = 0)]}; Log2: PUBLIC PROC [n: INT] RETURNS [INT] = {RETURN [IF n<=1 THEN 0 ELSE 1 + Log2[n / 2]]}; TwoToThe: PUBLIC PROC [x: INT] RETURNS [INT] = {RETURN[PowersOfTwo[x]]}; TwoToTheLog2: PUBLIC PROC [n: INT] RETURNS [INT] = {RETURN [TwoToThe[Log2[n]]]}; XthBitOfN: PUBLIC PROC [x, n: INT] RETURNS [BOOL] = {RETURN [IF x<0 THEN FALSE ELSE (n/TwoToThe[x]) MOD 2 =1]}; RunGenerator: PROC [comm: CDSequencer.Command] = { design: CD.Design _ comm.design; pos: CD.Position _ comm.pos; context: CDGenerate.Context _ CDGenerate.AssertContext["PatchWork"]; key: Rope.ROPE; ob: CD.Object; time: BasicTime.GMT _ BasicTime.Now[]; -- Start the stop watch min, sec: INT; TerminalIO.PutF["PatchWork menu selected\n"]; key _ CDGenerate.SelectOneOf[context, "select generate"]; IF Rope.IsEmpty[key] THEN {TerminalIO.PutF["no generator selected\n"]; RETURN}; ob _ CDGenerate.FetchNCall[context, design, key ! AbutProblem => {AbutError[design, ob1, ob2, what, isX, pos]; CONTINUE}]; sec _ BasicTime.Period[time, BasicTime.Now[]]; min _ sec/60; sec _ sec MOD 60; TerminalIO.PutF["PW completed in "]; IF min#0 THEN TerminalIO.PutF["%g min ", IO.int[min]]; TerminalIO.PutF["%g sec\n", IO.int[sec]]; IF ob=NIL THEN {TerminalIO.PutF["No returned object\n"]; RETURN}; CDOps.IncludeObjectI[design, ob, pos]; CDCleanUp.CleanUp[design]; }; AbutError: PROC [design: CD.Design, obj1, obj2: CD.Object, what: ROPE, isX: BOOL, where: CD.Position _ [0, 0]] = BEGIN translation: CD.Position _ CD.InterestSize[obj1]; IF isX THEN translation.y _ 0 ELSE translation.x _ 0; TerminalIO.PutF["PW Error while abuting '%g' and object '%g': %g\n", IO.rope[CDDirectory.Name[obj1]], IO.rope[CDDirectory.Name[obj2]], IO.rope[what]]; TerminalIO.PutF["Repaint the viewer to see the objects\n"]; CDOps.IncludeObjectI[design, obj1, where]; IF isX THEN translation.y _ 0 ELSE translation.x _ 0; CDOps.IncludeObjectI[design, obj2, CDBasics.AddPoints[where, translation]]; ERROR; END; ListMatchingCells: PROC [comm: CDSequencer.Command] = { EachEntry: CDDirectory.EachEntryAction = { count _ count+1; IF NOT Rope.Match[match, name, FALSE] THEN RETURN; displayed _ displayed+1; list _ CONS [ WITH ob.specific SELECT FROM cp: CD.CellSpecific => cp.name, ENDCASE => IO.PutFR["%g[%g]", IO.rope[name], IO.rope[CDOps.ObjectRope[ob]]], list]; }; match: ROPE; list: LIST OF Rope.ROPE _ NIL; count: INT _ 0; displayed: INT _ 0; TerminalIO.PutF["List matching objects\n"]; match _ TerminalIO.RequestRope["Pattern : "]; [] _ CDDirectory.Enumerate[comm.design, EachEntry]; list _ RopeList.Sort[list, RopeList.Compare]; FOR l: LIST OF Rope.ROPE _ list, l.rest WHILE l#NIL DO TerminalIO.PutF[" %g", IO.rope[l.first]]; ENDLOOP; TerminalIO.PutF["\n %g objects counted %g displayed\n", IO.int[count], IO.int[displayed]]; }; ListIcons: PROC [comm: CDSequencer.Command] = { EachEntry: CDDirectory.EachEntryAction = { count _ count+1; IF NOT Rope.Match["*.icon", name, FALSE] THEN RETURN; IF NOT Ascii.Letter[Rope.Fetch[name]] AND NOT Ascii.Digit[Rope.Fetch[name]] THEN RETURN; displayed _ displayed+1; list _ CONS [ WITH ob.specific SELECT FROM cp: CD.CellSpecific => cp.name, ENDCASE => IO.PutFR["%g[%g]", IO.rope[name], IO.rope[CDOps.ObjectRope[ob]]], list]; }; list: LIST OF Rope.ROPE _ NIL; count: INT _ 0; displayed: INT _ 0; TerminalIO.PutF["List icons\n"]; [] _ CDDirectory.Enumerate[comm.design, EachEntry]; list _ RopeList.Sort[list, RopeList.Compare]; FOR l: LIST OF Rope.ROPE _ list, l.rest WHILE l#NIL DO TerminalIO.PutF[" %g", IO.rope[l.first]]; ENDLOOP; TerminalIO.PutF["\n %g objects counted %g displayed\n", IO.int[count], IO.int[displayed]]; }; CDCommandOps.RegisterWithMenu[$DirectoryMenu, "list matching cells", "patterns OK. case NoN SignIFiCaNt", NIL, ListMatchingCells, dontQueue]; CDCommandOps.RegisterWithMenu[$DirectoryMenu, "list icons", "lists cells of the form *.icon", NIL, ListIcons, dontQueue]; CDSequencer.ImplementCommand[$PatchWork, RunGenerator]; CDCommandOps.RegisterWithMenu[$RectProgramMenu, "PatchWork generator", "proposes a menu of generators", $PatchWork]; TerminalIO.PutF["PatchWork generator recorded.\n"]; [] _ PWObjects.RegisterProp[$DontFlatten, TRUE]; FlushSharedCache[]; END. PWImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Created by: Monier, June 24, 1985 4:30:52 pm PDT Louis Monier August 22, 1985 12:39:11 pm PDT Bertrand Serlet December 17, 1986 11:35:04 pm PST Types and signals Utilities -- Reverse a list of objects Safe subset -- All flavors of Abut -- Clean the list and check that they match in size -- Clean the list and compare the sizes -- just before looping -- Arrays and other repetitions, using simple Abut. (other flavors of Abut ???) make a row create the object corresponding to the row create the tile corresponding to the set of rows -- This is a particular case where we want to attach to an object a property logically attached to an application: orientation, instance name, ... -- For mapping rectangles -- Planar tranformations -- Open a design, given a file name -- for now, nothing is checked -- Registration of UserProc: this creates the entry "Run MyWondeful generator" in the menu Shared abuts Novice users, please skip this section -- Adds the properties of obj which are copiable to the ones of newObj Tools for helping the designer debug his PW/Core code viewer: ViewerClasses.Viewer; design _ CDOps.CreateDesign[CD.FetchTechnology[IF technologyName=NIL THEN $cmosB ELSE technologyName]]; CDValue.Store[design, $KeepObjects, $KeepObjects]; -- to avoid finalization CDOps.IncludeObjectI[design, obj, [0, 0]]; viewer _ CDViewer.CreateViewer[design]; Goodies -- Input and output from the terminal -- The arithmetic stuff that people always want Warning: bit 0 is the LOW order bit (lsb) Commands -- PW heart: this one really make abuts by calling the user proc. -- Generate the object -- Now figure out how long it took to generate this wonderful piece of layout -- Scream -- Show the objects Directory list Initialization สย˜– "Cedar" stylešœ ™ Jšœ ฯmœ1™Jšœ žœ˜Jšœ-˜-Jšœ:˜:Jšžœžœ.žœ˜OJ™Jšœožœ˜zJ™MJšœ.˜.Jšœžœ˜Jšœ$˜$Jšžœžœžœ(žœ ˜`Jšžœžœžœ+žœ˜AJšœ&˜&Jšœ˜Jšœ˜—J˜šŸ œžœ žœžœžœžœ žœ˜pJšž˜Jšœ žœ žœ˜1Jšžœžœžœ˜5J™ JšœEžœžœžœ ˜–Jšœ;˜;J™Jšœ*˜*Jšžœžœžœ˜5JšœK˜KJšžœ˜Jšžœ˜———š ™šŸœžœ ˜7šะbn œ!˜*Kšœ˜Kš žœžœžœžœžœ˜2Kšœ˜šœžœ˜ Kšžœ žœžœžœžœžœžœ žœ˜ŠKšœ˜—Kšœ˜K˜—Kšœžœ˜ Kš œžœžœžœžœ žœžœ˜BKšœ+˜+K˜-Kšœ3˜3Kšœ-˜-š žœžœžœžœžœžœž˜6Kšœžœ˜*Kšžœ˜—Kšœ:žœ žœ˜\Kšœ˜K˜—šŸ œžœ ˜/šฃ œ!˜*Kšœ˜Kš žœžœžœžœžœ˜5Kš žœžœ žœžœžœžœ˜XKšœ˜šœžœ˜ Kšžœ žœžœžœžœžœžœ žœ˜ŠKšœ˜—Kšœ˜K˜—Kš œžœžœžœžœ žœžœ˜BKšœ ˜ Kšœ3˜3Kšœ-˜-š žœžœžœžœžœžœž˜6Kšœžœ˜*Kšžœ˜—Kšœ:žœ žœ˜\Kšœ˜——š ™Kšœkžœ ˜ŽKšœ^žœ˜yJšœ7˜7Jšœu˜uJšœ3˜3Jšœ*žœ˜0Jšœ˜J˜Jšžœ˜J™——…—1าJฐ