DIRECTORY Ascii, BasicTime, CD, CDBasics, CDCells, CDCleanUp, CDDirectory, CDEvents, CDGenerate, CDInstances, CDIO, CDMenus, CDOps, CDOrient, CDProperties, CDRects, CDSequencer, CDSymbolicObjects, CDValue, CDViewer, Commander, GList, HashTable, IO, PW, PWObjects, PWPins, RedBlackTree, Rope, RopeList, TerminalIO, ViewerClasses; PWImpl: CEDAR PROGRAM IMPORTS Ascii, BasicTime, CD, CDBasics, CDCells, CDCleanUp, CDDirectory, CDEvents, CDGenerate, CDIO, CDInstances, CDMenus, CDOps, CDOrient, CDProperties, CDRects, CDSequencer, CDSymbolicObjects, CDValue, CDViewer, Commander, GList, HashTable, IO, PW, PWPins, PWObjects, RedBlackTree, Rope, RopeList, TerminalIO EXPORTS PW = BEGIN OPEN PW; AbutProblem: PUBLIC SIGNAL [what: ROPE, isX: BOOL, ob1, ob2: Object] = CODE; Reverse: PUBLIC PROC [listObj: ListOb] RETURNS [result: ListOb _ NIL] = { result _ NARROW [GList.Reverse[listObj]]; }; CleanAndCheck: PROC [listObj: ListOb, isX: BOOL] RETURNS [newListObj: ListOb _ NIL] = BEGIN size, prSize: INT _ -1; prObj, obj: Object; IF listObj=NIL THEN RETURN[NIL]; -- the list was NIL WHILE listObj#NIL DO obj _ listObj.first; IF obj=NIL THEN {listObj _ listObj.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 newListObj _ CONS [obj, newListObj]; -- build clean list (reversed) IF prSize<0 THEN {prSize _ size; prObj _ obj; listObj _ listObj.rest; LOOP}; -- first time IF prSize#size THEN AbutProblem["These two objects do not match\n", isX, prObj, obj]; prSize _ size; prObj _ obj; listObj _ listObj.rest; ENDLOOP; newListObj _ Reverse[newListObj]; END; AbutX: PUBLIC PROC [t1,t2,t3,t4,t5,t6: Object _ NIL] RETURNS [obj: Object] = {listOb: ListOb _ NIL; RETURN [AbutListX[LIST[t1,t2,t3,t4,t5,t6]]]}; AbutY: PUBLIC PROC [t1,t2,t3,t4,t5,t6: Object _ NIL] RETURNS [obj: Object] = { listOb: ListOb _ NIL; RETURN [AbutListY[LIST[t1,t2,t3,t4,t5,t6]]]; }; AbutListX: PUBLIC PROC [listOb: ListOb] RETURNS [obj: Object] = { listOb _ CleanAndCheck[listOb, TRUE]; obj _ IF listOb=NIL THEN NIL ELSE PWObjects.CreateNewAbutX[listOb]; }; AbutListY: PUBLIC PROC [listOb: ListOb] RETURNS [obj: Object] = { listOb _ CleanAndCheck[listOb, FALSE]; obj _ IF listOb=NIL THEN NIL ELSE PWObjects.CreateNewAbutY[listOb]; }; Lexico: TYPE = REF LexicoRec; LexicoRec: TYPE = RECORD [loc: INT, size: INT, layer: CD.Layer]; GetKey: RedBlackTree.GetKey = { RETURN[data]; }; Compare: RedBlackTree.Compare = { key: Lexico _ NARROW[data]; kk: Lexico _ NARROW[k]; SELECT TRUE FROM kk.loc RETURN[less]; kk.loc>key.loc => RETURN[greater]; kk.size RETURN[less]; kk.size>key.size => RETURN[greater]; kk.layer RETURN[less]; kk.layer>key.layer => RETURN[greater]; ENDCASE => RETURN[equal]; -- should this be an error??? }; CheckPair: PROC [t1, t2: Object _ NIL, isX: BOOL] = BEGIN table1, table2: RedBlackTree.Table; MakeLexico: PROC[inst: Instance, obj: Object] RETURNS [Lexico] = { k: Lexico _ NEW [LexicoRec _ [ IF isX THEN GetLocation[inst, obj].y ELSE GetLocation[inst, obj].x, IF isX THEN CDOrient.OrientedSize[inst.ob.size, inst.orientation].y ELSE CDOrient.OrientedSize[inst.ob.size, inst.orientation].x, CDSymbolicObjects.GetLayer[inst]]]; RETURN[k]; }; ParseT1: PWPins.InstanceEnumerator = { IF PWPins.GetSide[t1, inst].side=(IF isX THEN right ELSE top) THEN {k: Lexico _ MakeLexico[inst, t1]; RedBlackTree.Insert[table1, k, k]}; }; ParseT2: PWPins.InstanceEnumerator = { IF PWPins.GetSide[t2, inst].side=(IF isX THEN left ELSE bottom) THEN {k: Lexico _ MakeLexico[inst, t2]; RedBlackTree.Insert[table2, k, k]}; }; CheckIfMatch: RedBlackTree.EachNode = { IF RedBlackTree.Lookup[table2, NARROW[data]]=NIL THEN AbutProblem["The pins of these two objects do not match\n", isX, t1, t2]; }; table1 _ RedBlackTree.Create[GetKey, Compare]; table2 _ RedBlackTree.Create[GetKey, Compare]; [] _ PWPins.EnumerateEdgePins[t1, ParseT1]; [] _ PWPins.EnumerateEdgePins[t2, ParseT2]; RedBlackTree.EnumerateIncreasing[table1, CheckIfMatch]; END; AbutCheckX: PUBLIC PROC [t1,t2,t3,t4,t5,t6: Object _ NIL] RETURNS [obj: Object] = {RETURN [AbutCheckListX[LIST[t1, t2, t3, t4, t5, t6]]]}; AbutCheckY: PUBLIC PROC [t1,t2,t3,t4,t5,t6: Object _ NIL] RETURNS [obj: Object] = {RETURN [AbutCheckListY[LIST[t1, t2, t3, t4, t5, t6]]]}; AbutCheckListX: PUBLIC PROC [listOb: ListOb] RETURNS [obj: Object] = {t1, t2: Object; saveListOb: ListOb; listOb _ CleanAndCheck[listOb, FALSE]; -- no more NILs IF listOb=NIL THEN RETURN[NIL]; saveListOb _ listOb; t1 _ listOb.first; listOb _ listOb.rest; WHILE listOb#NIL DO -- check adjacent pairs of edges t2 _ listOb.first; CheckPair[t1, t2, TRUE]; -- will raise an error if mismatch t1 _ t2; listOb _ listOb.rest; ENDLOOP; obj _ PWObjects.CreateNewAbutX[saveListOb]; }; AbutCheckListY: PUBLIC PROC [listOb: ListOb] RETURNS [obj: Object] = {t1, t2: Object; saveListOb: ListOb; listOb _ CleanAndCheck[listOb, FALSE]; -- no more NILs IF listOb=NIL THEN RETURN[NIL]; saveListOb _ listOb; t1 _ listOb.first; listOb _ listOb.rest; WHILE listOb#NIL DO t2 _ listOb.first; CheckPair[t1, t2, FALSE]; -- will raise an error if mismatch t1 _ t2; listOb _ listOb.rest; ENDLOOP; obj _ PWObjects.CreateNewAbutY[saveListOb]; }; MapFunctionX: PUBLIC PROC [function: XYFunction, lx: INT _ 0, ux: INT] RETURNS [new: Object] = BEGIN row: ListOb _ 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: ListOb _ 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: ListOb _ NIL; IF lx>=ux OR ly>=uy THEN RETURN[NIL]; FOR y: INT DECREASING IN [ly .. uy) DO row: ListOb _ 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; MapFunctionIndexPins: PUBLIC PROC [function: XYFunction, lx: INT _ 0, ux: INT, ly: INT _ 0, uy: INT, indexedPins: ARRAY PWPins.Side OF LIST OF ROPE _ ALL [NIL]] RETURNS [new: Object] = { rows: ListOb _ NIL; IF lx>=ux OR ly>=uy THEN RETURN[NIL]; FOR y: INT DECREASING IN [ly .. uy) DO row: ListOb _ NIL; FOR x: INT DECREASING IN [lx .. ux) DO ob: Object _ function[x, y]; ChangePin: PWPins.ChangePinProc = { side: PWPins.Side _ PWPins.GetSide[ob, oldPin]; name: ROPE _ CDSymbolicObjects.GetName[oldPin]; IF (SELECT side FROM bottom => y#ly, right => x#ux-1, top => y#uy-1, left => x#lx, ENDCASE => ERROR) THEN RETURN; newPin _ CDInstances.Copy[oldPin]; IF ~RopeList.Memb[indexedPins[side], name] THEN RETURN; CDSymbolicObjects.SetName[newPin, IO.PutFR["%g[%g]", IO.rope[name], IO.int[SELECT side FROM bottom, top => x, right, left => y, ENDCASE => ERROR]]]; }; row _ CONS [PWPins.ChangePins[ob, ChangePin], row]; ENDLOOP; rows _ CONS [AbutListX[row], rows]; ENDLOOP; RETURN [AbutListY[rows]]; }; 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: CDOrient.Orientation] RETURNS [cell: CD.Object] = BEGIN cell _ CreateEmptyCell[]; [] _ IncludeInCell[cell: cell, obj: obj, orientation: orientation]; RepositionCell[cell]; END; InstanceName: PUBLIC PROC [obj: Object, instanceName: ROPE] RETURNS [cell: Object] = BEGIN appl: CD.Instance; cell _ CreateEmptyCell[]; appl _ IncludeInCell[cell: cell, obj: obj]; CDProperties.PutInstanceProp[appl, $InstanceName, instanceName]; RepositionCell[cell]; END; CopyAndProcess: PROC [ob: CD.Object, p: ForEachInstProc _ NIL, data: REF _ NIL] RETURNS [new: CD.Object] = BEGIN Insert: PROC [inst: CD.Instance, location: CD.Position] = BEGIN IF inst#NIL THEN { newInst: CD.Instance _ IncludeInCell[new, inst.ob, location, inst.orientation]; newInst.properties _ CDProperties.DCopyProps[inst.properties];}; END; ExpandInCell: PROC [ob: Object] RETURNS [cell: Object] = {cell _ IF CDCells.IsCell[ob] THEN ob ELSE CDDirectory.Expand[ob, NIL, NIL].new}; location: CD.Position; WHILE ~ISTYPE[ob.specificRef, CD.CellPtr] DO ob _ CDDirectory.Expand[ob, NIL, NIL].new ENDLOOP; new _ CreateEmptyCell[]; CDCells.SetInterestRect[new, CD.InterestRect[ob]]; -- copy the IRect FOR instances: CD.InstanceList _ NARROW [ExpandInCell[ob].specificRef, CD.CellPtr].contents, instances.rest WHILE instances # NIL DO inst: CD.Instance _ instances.first; location _ GetLocation[inst, ob]; IF p#NIL THEN Insert[p[inst, data], location] ELSE Insert[inst, location]; ENDLOOP; AppendProps[new, ob]; RepositionCell[new]; END; Copy: PUBLIC PROC [ob: Object] RETURNS [new: Object] = {new _ CopyAndProcess[ob]}; Inst: PUBLIC PROC [ob: Object, conds: LIST OF ROPE _ NIL, removeNamed: BOOL _ TRUE] RETURNS [new: Object] = BEGIN ConditionalObjProc: PW.ForEachInstProc = BEGIN ref: REF _ CDProperties.GetInstanceProp[inst, $PWCond]; IF ref = NIL THEN RETURN[inst] -- this instance is not conditional ELSE BEGIN rec: Data _ NARROW[data]; WITH ref SELECT FROM prop: ROPE => BEGIN -- it is a conditionnal object; see if it is listed listed: BOOL _ FALSE; FOR list: LIST OF ROPE _ rec.conds, list.rest WHILE list # NIL DO IF Rope.Equal[list.first, prop] THEN listed _ TRUE; ENDLOOP; -- standard in PWNames !!! IF listed # rec.removeNamed THEN RETURN[inst] ELSE RETURN[NIL]; END; ENDCASE => RETURN[inst]; END; END; Data: TYPE = REF DataRec; DataRec: TYPE = RECORD[conds: LIST OF ROPE _ NIL, removeNamed: BOOL _ TRUE]; data: Data _ NEW[DataRec _ [conds, removeNamed]]; new _ CopyAndProcess[ob, ConditionalObjProc, data]; END; Flatten: PUBLIC PROC [cell: Object] RETURNS [new: Object] = BEGIN 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]]; }; new _ CDCells.CreateEmptyCell[]; FOR appls: CD.InstanceList _ NARROW [cell.specificRef, CD.CellPtr].contents, appls.rest WHILE appls # NIL DO inst: CD.Instance; ap: CD.Instance _ appls.first; ob: Object _ Flatten[ap.ob]; location: CD.Position _ GetLocation[ap, cell]; -- Interest Coord of ap.ob in the Interest Coord system of cell IF NOT CDCells.IsCell[ob] OR CDProperties.GetObjectProp[ob, $DontFlatten]#NIL THEN {-- it's not a cell: copy it inst _ PW.IncludeInCell[new, ob, location, ap.orientation]; inst.properties _ CDProperties.DCopyProps[ap.properties]; } ELSE FOR l: CD.InstanceList _ NARROW [ob.specificRef, CD.CellPtr].contents, l.rest WHILE l # NIL DO inst _ PW.IncludeInCell[ new, l.first.ob, CDBasics.BaseOfRect[CDOrient.MapRect[ CDOrient.RectAt[GetLocation[l.first, ob], CD.InterestSize[l.first.ob], l.first.orientation], CD.InterestSize[ob], ap.orientation, location ]], CDOrient.ComposeOrient[l.first.orientation, ap.orientation]]; inst.properties _ CDProperties.DCopyProps[l.first.properties]; ENDLOOP; ENDLOOP; SetInterestRect[new, CD.InterestSize[cell]]; -- copy the IRect AppendProps[new, cell]; RepositionCell[new]; END; 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 {WriteF["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; CopyRecursive: PROC [old: Object] RETURNS [new: Object] = { new _ CDDirectory.Another[old, NIL, NIL].new; IF CDCells.IsCell[old] THEN { cellPtr: CD.CellPtr _ NARROW [new.specificRef]; FOR list: CD.InstanceList _ cellPtr.contents, list.rest WHILE list#NIL DO list.first.ob _ CopyRecursive[list.first.ob]; ENDLOOP; }; }; Register: PUBLIC PROC [userProc: UserProc, name: ROPE] = { WriteF["Generator program %g %g.\n", IO.rope[name], IO.rope[ IF CDGenerate.Register[table: CDGenerate.AssertTable["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 [listOb: ListOb] RETURNS [obj: Object] = { revList: ListOb _ NIL; IF listOb=NIL THEN RETURN [NIL]; IF listOb.rest=NIL THEN RETURN [listOb.first]; WHILE listOb#NIL AND listOb.rest#NIL DO revList _ CONS [SharedAbutX[listOb.first, listOb.rest.first], revList]; listOb _ listOb.rest.rest; ENDLOOP; IF listOb#NIL THEN revList _ CONS [listOb.first, revList]; obj _ SharedAbutListX[Reverse[revList]]; }; SharedAbutListY: PUBLIC PROC [listOb: ListOb] RETURNS [obj: Object] = { revList: ListOb _ NIL; IF listOb=NIL THEN RETURN [NIL]; IF listOb.rest=NIL THEN RETURN [listOb.first]; WHILE listOb#NIL AND listOb.rest#NIL DO revList _ CONS [SharedAbutY[listOb.first, listOb.rest.first], revList]; listOb _ listOb.rest.rest; ENDLOOP; IF listOb#NIL THEN revList _ CONS [listOb.first, revList]; obj _ SharedAbutListY[Reverse[revList]]; }; FlushSharedCache: PUBLIC PROC = { sharedAbutXCache _ HashTable.Create[2]; sharedAbutYCache _ HashTable.Create[2]; }; propertiesToFlushOnEdit: LIST OF ATOM _ NIL; RegisterProp: PUBLIC PROC [prop: ATOM, copy: BOOL _ FALSE, flushOnEdit: BOOL _ FALSE] RETURNS [sameAtom: ATOM] = { [] _ CDProperties.RegisterProperty[prop, $PW]; CDProperties.InstallProcs[prop, [makeCopy: IF copy THEN CDProperties.CopyVal ELSE CDProperties.DontCopy]]; IF flushOnEdit THEN propertiesToFlushOnEdit _ CONS [prop, propertiesToFlushOnEdit]; sameAtom _ prop; }; IncludeInCell: PUBLIC PROC [cell: Object, obj: Object, position: CD.Position _ [0, 0], orientation: CD.Orientation _ CD.original] RETURNS [newInst: Instance] = BEGIN newInst _ CDCells.IncludeOb[design: NIL, cell: cell, ob: obj, position: position, orientation: orientation, cellCSystem: interrestCoords, obCSystem: interrestCoords, mode: dontPropagate].newInst END; 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; }; IncludeNoReposition: PROC [design: CD.Design, obj: Object, name: ROPE _ NIL] = {IF design#NIL THEN [] _ CDDirectory.Include[design, obj, name]}; GetLocation: PUBLIC PROC [inst: CD.Instance, obj: CD.Object] RETURNS [location: CD.Position] = {location _ CDBasics.SubPoints[ CDBasics.BaseOfRect[ CDOrient.MapRect[CD.InterestRect[inst.ob], inst.ob.size, inst.orientation, inst.location]], CDBasics.BaseOfRect[CD.InterestRect[obj]]]}; Send: PUBLIC PROC [obj: Object, prop: ATOM] RETURNS [value: REF _ NIL, expandedObj: Object] = { expandedObj _ obj; WHILE value=NIL DO IF expandedObj=NIL THEN RETURN; value _ CDProperties.GetObjectProp[expandedObj, prop]; IF value#NIL THEN RETURN; value _ CDProperties.GetProp[expandedObj.class, prop]; IF value#NIL THEN RETURN; expandedObj _ CDDirectory.Expand[expandedObj, NIL, NIL].new; ENDLOOP; }; TransferCell: PUBLIC PROC [template: Object, objSide: PWPins.Side, width: INT, objProc: ForEachPinProc, selectNameProc: SelectNamesProc _ KeepAll] RETURNS [cell: Object] = BEGIN KeepPinOnEdge: PWPins.InstanceEnumerator = BEGIN newObj: Object; side: PWPins.Side _ PWPins.GetSide[template, inst].side; IF side=objSide AND selectNameProc[CDSymbolicObjects.GetName[inst]] THEN { newObj _ objProc[inst]; IF newObj=NIL THEN RETURN; [] _ IncludeInCell[cell, newObj, Position[inst, template, objSide], SideToOrient[objSide]]; }; END; iRect: CD.Rect; IF objSide=none THEN ERROR; cell _ CreateEmptyCell[]; iRect _ CD.InterestRect[template]; -- copy interestRect of obj CDCells.SetInterestRect[cell, IRect[iRect, width, objSide]]; -- set interestRect of cell [] _ PWPins.EnumerateEdgePins[template, KeepPinOnEdge]; RepositionCell[cell]; END; IRect: PROC [templateRect: CD.Rect, otherDim: INT, side: PWPins.Side] RETURNS [iRect: CD.Rect] = BEGIN iRect _ SELECT side FROM top, bottom => [0, 0, templateRect.x2-templateRect.x1, otherDim], left, right => [0, 0, otherDim, templateRect.y2-templateRect.y1], ENDCASE => ERROR; END; WireSize: PROC [inst: CD.Instance, otherDim: INT, side: PWPins.Side] RETURNS [size: CD.Position] = BEGIN size _ CDOrient.OrientedSize[inst.ob.size, inst.orientation]; -- may be inst.ob.size should be CD.InterestSize[inst.ob] for pdif ??? SELECT side FROM top, bottom => size _ [otherDim, size.x]; left, right => size _ [otherDim, size.y]; ENDCASE => ERROR; END; Position: PROC [inst: CD.Instance, template: Object, side: PWPins.Side] RETURNS [position: CD.Position] = BEGIN position _ GetLocation[inst, template]; SELECT side FROM top, bottom => position.y _ 0; left, right => position.x _ 0; ENDCASE => ERROR; END; SideToOrient: PROC [side: PWPins.Side] RETURNS [orient: CD.Orientation] ~ { orient _ SELECT side FROM bottom => CDOrient.rotate270, right => CDOrient.original, top => CDOrient.rotate90, left => CDOrient.rotate180, ENDCASE => ERROR; }; KeepAll: PUBLIC SelectNamesProc = {keepIt _ TRUE}; TopFillerCell: PUBLIC PROC [template: Object, height: INT, selectNameProc: SelectNamesProc _ KeepAll] RETURNS [cell: Object] = {cell _ FillerCell[template, top, height, selectNameProc]}; BottomFillerCell: PUBLIC PROC [template: Object, height: INT, selectNameProc: SelectNamesProc _ KeepAll] RETURNS [cell: Object] = {cell _ FillerCell[template, bottom, height, selectNameProc]}; LeftFillerCell: PUBLIC PROC [template: Object, width: INT, selectNameProc: SelectNamesProc _ KeepAll] RETURNS [cell: Object] = {cell _ FillerCell[template, left, width, selectNameProc]}; RightFillerCell: PUBLIC PROC [template: Object, width: INT, selectNameProc: SelectNamesProc _ KeepAll] RETURNS [cell: Object] = {cell _ FillerCell[template, right, width, selectNameProc]}; FillerCell: PROC [template: Object, objSide: PWPins.Side, width: INT, selectNameProc: SelectNamesProc _ KeepAll] RETURNS [cell: Object] = BEGIN ObjProc: ForEachPinProc = { obj _ CDRects.CreateRect[WireSize[inst, width, objSide], CDSymbolicObjects.GetLayer[inst]]; }; cell _ TransferCell[template, objSide, width, ObjProc, selectNameProc]; END; Draw: PUBLIC PROC [obj: CD.Object, technologyName: ATOM _ NIL] RETURNS [design: CD.Design] = { 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]; }; 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; table: CDGenerate.Table _ CDGenerate.AssertTable["PatchWork"]; key: Rope.ROPE; ob: CD.Object; time: BasicTime.GMT _ BasicTime.Now[]; -- Start the stop watch min, sec: INT; WriteF["PatchWork menu selected\n"]; key _ CDGenerate.SelectOneOf[table, "select generate"]; IF Rope.IsEmpty[key] THEN {WriteF["no generator selected\n"]; RETURN}; ob _ CDGenerate.FetchNCall[table, design, key ! AbutProblem => {AbutError[design, ob1, ob2, what, isX, pos]; CONTINUE}]; sec _ BasicTime.Period[time, BasicTime.Now[]]; min _ sec/60; sec _ sec MOD 60; WriteF["PW completed in "]; IF min#0 THEN WriteF["%g min ", IO.int[min]]; WriteF["%g sec\n", IO.int[sec]]; IF ob=NIL THEN {WriteF["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; WriteF["PW Error while abuting '%g' and object '%g': %g\n", IO.rope[CDDirectory.Name[obj1]], IO.rope[CDDirectory.Name[obj2]], IO.rope[what]]; WriteF["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]]; IF TerminalIO.Confirm[choice: "Do you want to open an error window for StackWalking?", label: "Open EventViewer?", onTimeOut: FALSE] THEN 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.specificRef SELECT FROM cp: CD.CellPtr => cp.name, ENDCASE => IO.PutFR["%g[%g]", IO.rope[name], IO.rope[CDOps.ObjectInfo[ob]]], list]; }; match: ROPE; list: LIST OF Rope.ROPE _ NIL; count: INT _ 0; displayed: INT _ 0; WriteF["List matching objects\n"]; match _ 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 WriteF[" %g", IO.rope[l.first]]; ENDLOOP; WriteF["\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.specificRef SELECT FROM cp: CD.CellPtr => cp.name, ENDCASE => IO.PutFR["%g[%g]", IO.rope[name], IO.rope[CDOps.ObjectInfo[ob]]], list]; }; list: LIST OF Rope.ROPE _ NIL; count: INT _ 0; displayed: INT _ 0; WriteF["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 WriteF[" %g", IO.rope[l.first]]; ENDLOOP; WriteF["\n %g objects counted %g displayed\n", IO.int[count], IO.int[displayed]]; }; PatchWorkCommand: Commander.CommandProc = { IO.PutF[cmd.out, "PatchWork loaded.\n"]; }; FlushPropertiesAfterReplace: CDEvents.EventProc = { xname: ROPE _ CDDirectory.Name[NARROW [x]]; names: LIST OF ROPE _ IF xname=NIL THEN NIL ELSE LIST [xname]; -- names is going to be the transitive closure of all cells depending on xname foundANewOne: BOOL _ TRUE; FindInvalidNames: CDDirectory.EachEntryAction = { someChildIsName: BOOL _ FALSE; IsSomeChildName: CDDirectory.EnumerateObjectsProc = { IF RopeList.Memb[names, CDDirectory.Name[me]] THEN someChildIsName _ TRUE; }; CDDirectory.EnumerateChildObjects[ob, IsSomeChildName]; IF someChildIsName AND ~RopeList.Memb[names, name] THEN {names _ CONS [name, names]; foundANewOne _ TRUE}; }; InvalidateNames: CDDirectory.EachEntryAction = { IF RopeList.Memb[names, name] THEN { flushed: BOOL _ FALSE; FOR props: LIST OF ATOM _ propertiesToFlushOnEdit, props.rest WHILE props#NIL DO flushed _ flushed OR (CDProperties.GetObjectProp[ob, props.first]#NIL); CDProperties.PutObjectProp[ob, props.first, NIL]; ENDLOOP; IF flushed THEN TerminalIO.WriteRope[Rope.Cat["Flush ", name, "\n"]]; }; }; WHILE foundANewOne DO foundANewOne _ FALSE; [] _ CDDirectory.Enumerate[design, FindInvalidNames]; ENDLOOP; [] _ CDDirectory.Enumerate[design, InvalidateNames]; }; CDMenus.ImplementEntryCommand[$DirectoryMenu, "list matching cells", ListMatchingCells]; CDMenus.ImplementEntryCommand[$DirectoryMenu, "list icons", ListIcons]; CDEvents.RegisterEventProc[$AfterCellReplacement, FlushPropertiesAfterReplace]; CDSequencer.ImplementCommand[$PatchWork, RunGenerator]; CDMenus.CreateEntry[$RectProgramMenu, "PatchWork generator", $PatchWork]; WriteF["PatchWork generator recorded.\n"]; Commander.Register["PW", PatchWorkCommand, "PatchWork, Silicon Assembler on top of ChipNDale, see PWDoc.tioga for more info!\n"]; [] _ PW.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 September 2, 1986 10:24:53 pm PDT This implemetation module contains the "safe" primitives accessible to the user, e.g. Abut. 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 -- key from data [data: RedBlackTree.UserData] RETURNS [RedBlackTree.Key] -- order is: coordinate, size, layer; name is not used [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison] -- key from Instance [inst: CD.Instance] RETURNS [quit: BOOL _ FALSE] -- [inst: CD.Instance] RETURNS [quit: BOOL _ FALSE] [data: RedBlackTree.UserData] RETURNS [stop: BOOL _ FALSE] -- scream if mismatch: this is not a complete test yet!!! -- create dictionnaries -- parse right edge of t1 and left edge of t2, and fill up the dictionnaries -- find pairs which match by position, size, and layer -- 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 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 -- Create a cell with obj as only application, and InstName as instance name -- Copy and conditional objects -- Make a copy of the cell "ob" where every instance ap is replaced by p[ap]; if p=NIL, the instance is unchanged -- Copies the application, and inserts it in "new" -- How about modif in IRect!!! -- We remove an object if it is listed and removeNamed=TRUE or if removeNamed=FALSE and it is not listed -- Other functions --Fetching a cell from a design -- Not perfectly safe, because if someone imports a cell, edits it, and imports it again, the version stamp is unchanged, so no conflict is detected. -- 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 You are on your own -- Include an object in a cell; position is relative to the InterestRect -- Adds the properties of obj which are copiable to the ones of newObj -- The following primitive allows the use of the interestRectangle coordinates only High-level constructors (safe if your procs are safe) -- Start with an empty cell of appropriate interestRect (origin in 0,0) -- Parse the pins Tools for helping the designer debug his PW/Core code 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 Mechanism for flushing during edits [event: REF ANY, design: CD.Design, x: REF ANY] RETURNS [dont: BOOL _ FALSE] [name: ROPE, ob: CD.Object] RETURNS [quit: BOOL _ FALSE] [me: CD.Object, x: REF ANY] [name: ROPE, ob: CD.Object] RETURNS [quit: BOOL _ FALSE] Κ$Ε˜– "Cedar" stylešœ ™ Jšœ Οmœ1™Kšœ#˜#—Kšžœ˜ Kšœ˜—–4 -- [inst: CD.Instance] RETURNS [quit: BOOL _ FALSE]šŸœ˜&Kšž0™0š žœ žœžœžœž˜BKšœF˜F—K˜—–4 -- [inst: CD.Instance] RETURNS [quit: BOOL _ FALSE]šŸœ˜&Kš’3™3š žœ žœžœžœ ž˜DKšœF˜F—K˜—–> -- [data: RedBlackTree.UserData] RETURNS [stop: BOOL _ FALSE]šŸ œ˜'Jš’:™:J™9šžœžœžœ˜1JšžœK˜O—J˜—J™Jšœ™Jšœ.˜.Jšœ.˜.JšœL™LJšœ+˜+Jšœ+˜+J™J™6Jšœ7˜7Jšžœ˜—J˜š Ÿ œžœžœžœžœ˜QJšœžœžœ˜8—š Ÿ œžœžœžœžœ˜QJšœžœžœ˜8—šŸœžœžœžœ˜DJšœ˜Jšœ˜Jšœžœ‘˜6Jš žœžœžœžœžœ˜Jšœ˜Jšœ)˜)šžœžœžœ‘ ˜4Jšœ˜Jšœžœ‘"˜;Jšœ˜Jšžœ˜—Jšœ+˜+Jšœ˜J˜—šŸœžœžœžœ˜DJšœ˜Jšœ˜Jšœžœ‘˜6Jš žœžœžœžœžœ˜Jšœ˜Jšœ)˜)šžœžœž˜Jšœ˜Jšœžœ‘"˜˜>—Jšžœ˜—Jšžœ˜—Jšœžœ‘˜>Jšœ˜Jšœ˜Jšžœ˜—J˜™J™J™•š Ÿœžœžœžœžœ˜FKšžœžœžœžœ˜Kšœ,˜,Kš žœžœžœ1žœžœ˜VK˜—J™J™#š Ÿ œžœžœ žœžœ žœ ˜FJšž˜J™Jšœ žœžœžœ˜DJšœ3‘˜KJšžœ˜—J™šŸ œžœžœ˜;Jšœžœžœ˜-šžœžœ˜Jšœ žœ žœ˜/š žœžœ,žœžœž˜IJšœ-˜-Jšžœ˜—J˜—J˜—J™šœZ™ZšŸœžœžœžœ˜:šœ%žœ žœ˜‘F˜„šžœž˜Jšœ)˜)Jšœ)˜)Jšžœžœ˜—Jšžœ˜—J˜š Ÿœžœžœ0žœ žœ ˜jJšž˜Jšœ'˜'šžœž˜Jšœ˜Jšœ˜Jšžœžœ˜—Jšžœ˜—šŸ œžœžœ žœ˜Kšœ žœž˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœžœ˜—K˜JšŸœžœžœ˜2š Ÿ œžœžœžœ-žœ˜Jšœ;˜;—š Ÿœžœžœžœ-žœ˜‚Jšœ>˜>—š Ÿœžœžœžœ-žœ˜Jšœ;˜;—š Ÿœžœžœžœ-žœ˜€Jšœ<˜<——™šŸ œžœ1žœ-žœ˜‰Jšž˜š£œ˜Jšœ[˜[Jšœ˜—JšœG˜GJšžœ˜———™5šŸœžœžœžœžœžœžœ žœ ˜^Kšœ˜Kš œžœžœžœžœžœ˜gJšœ3‘˜KKšœ*˜*Kšœ'˜'K˜——š ™J™%J˜šœ/™/šŸ œžœ žœžœ˜'Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜—J˜š Πbkœžœžœžœžœžœ˜+Jšœžœžœ ˜—š €œžœžœžœžœžœ˜,Jšœžœžœ ˜—š Ÿœžœžœžœžœžœ˜*Jš œžœžœžœžœ˜/—š Ÿœžœžœžœžœžœ˜.Jšœžœ˜—š Ÿ œžœžœžœžœžœ˜3Jšœžœ˜—š Ÿ œžœžœžœžœžœ˜3Jšœ)™)Jš œžœžœžœžœžœžœ˜;———š ™™AšŸ œžœ ˜2Jšœžœ˜ Jšœžœ˜Jšœ>˜>Jšœ žœ˜Jšœžœ˜Jšœžœ‘˜>Jšœ žœ˜Jšœ$˜$Jšœ8˜8Jšžœžœ%žœ˜FJ™Jšœmžœ˜xJ™MJšœ.˜.Jšœžœ˜Jšœ˜Jšžœžœžœžœ ˜NJšžœžœžœ"žœ˜8Jšœ&˜&Jšœ˜Jšœ˜—J˜šŸ œžœ žœžœžœžœ žœ˜pJšž˜Jšœ žœ žœ˜1Jšžœžœžœ˜5J™ Jšœ<žœžœžœ ˜Jšœ2˜2J™Jšœ*˜*Jšžœžœžœ˜5JšœK˜KJšžœ|žœžœžœ˜Jšžœ˜———š ™šŸœžœ ˜7š£ œ!˜*Kšœ˜Kš žœžœžœžœžœ˜2Kšœ˜šœžœ˜ Kšžœžœžœžœžœžœžœ žœ˜ˆKšœ˜—Kšœ˜K˜—Kšœžœ˜ Kš œžœžœžœžœ žœžœ˜BKšœ"˜"K˜"Kšœ3˜3Kšœ-˜-š žœžœžœžœžœžœž˜6Kšœžœ˜!Kšžœ˜—Kšœ1žœ žœ˜SKšœ˜K˜—šŸ œžœ ˜/š£ œ!˜*Kšœ˜Kš žœžœžœžœžœ˜5Kš žœžœ žœžœžœžœ˜XKšœ˜šœžœ˜ Kšžœžœžœžœžœžœžœ žœ˜ˆKšœ˜—Kšœ˜K˜—Kš œžœžœžœžœ žœžœ˜BKšœ˜Kšœ3˜3Kšœ-˜-š žœžœžœžœžœžœž˜6Kšœžœ˜!Kšžœ˜—Kšœ1žœ žœ˜SKšœ˜——š ™š£œ˜+Jšžœ&˜(J˜J˜—Jšœ#™#š£œ˜3Jš’L™LJšœžœžœ˜+Jšœžœžœžœžœžœžœžœžœžœ ‘N˜J–< -- [name: ROPE, ob: CD.Object] RETURNS [quit: BOOL _ FALSE]šœžœžœ˜š£œ!˜1Jš’8™8Jšœžœžœ˜– -- [me: CD.Object, x: REF ANY]š£œ&˜5Jš’™Jšžœ,žœžœ˜JJ˜—Jšœ7˜7Jš žœžœžœ žœžœ˜jJ˜—–< -- [name: ROPE, ob: CD.Object] RETURNS [quit: BOOL _ FALSE]š£œ!˜0Jš’8™8šžœžœ˜$Jšœ žœžœ˜š žœžœžœžœ'žœžœž˜PJšœžœ.žœ˜GJšœ,žœ˜2Jšžœ˜—Jšžœ žœ6˜EJ˜—J˜—šžœžœ˜Jšœžœ7˜KJšžœ˜—Jšœ5˜5J˜—J˜KšœX˜XKšœG˜GJšœO˜OJšœ7˜7JšœJ˜JJšœ*˜*Jšœ˜Jšœžœžœ˜)Jšœ˜J˜Jšžœ˜J™——…—f2˜Ώ