PW.mesa 
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Louis Monier August 22, 1985 12:23:42 pm PDT
Bertrand Serlet February 6, 1986 11:45:37 am PST
-- PatchWork (PW) is a Silicon Assembler.
DIRECTORY
CD USING [Design, Instance, InstanceList, Object, original, Position],
CDCells USING [CreateEmptyCell, RepositionCell],
CDCleanUp USING [CleanUp],
CDGenerate USING [GeneratorProc],
CDOrient USING [mirrorX, mirrorY, Orientation, rotate90, rotate180, rotate270],
IO USING [Value],
PWPins USING [Side],
Rope USING [ROPE],
TerminalIO;
PW: CEDAR DEFINITIONS
IMPORTS CDCells, CDCleanUp, TerminalIO =
BEGIN
Types and signals
ROPE: TYPE = Rope.ROPE; -- Unavoidable
-- The new hot types, identical to CD types
Object: TYPE = CD.Object;      -- an object, i.e. a definition  
ListOb: TYPE = LIST OF Object;
Instance: TYPE = CD.Instance;    -- an instance
InstanceList: TYPE = CD.InstanceList;
Design: TYPE = CD.Design;
UserProc: TYPE = CDGenerate.GeneratorProc; -- PROC [design: Design, key: ROPE, table: CDGenerate.Table, data: REF] RETURNS [ob: Object←NIL]
What the user registers with PW
AbutProblem: SIGNAL [what: ROPE, isX: BOOL, ob1, ob2: Object];
-- This signal might be raised by an incorrect abut
Utilities
Reverse: PUBLIC PROC [listObj: ListOb] RETURNS [result: ListOb ← NIL];
ListOb manipulations
ForEachInstProc: TYPE = PROC [inst: Instance, data: REF] RETURNS [newInst: Instance ← NIL];
-- Used in enumeration procs, for example by conditional objects
Safe subset
-- The use of this subset is safe in the following sense: if a novice user (i.e. not Christian Jacobi or Don Curry) creates interactively cells with ChipNDale, and assembles them using only Abuts, MapFunction, and the like, then the resulting design is not going to give him any trouble: it should display, plot and turn into CIF with no complication.
-- Abuts: the following procs create an Abut, which is not a cell, but a new class of CD object.
-- All these proc can raise the signal AbutProblem
-- The simple abutment uses the interestrect; it stops and complains if size mismatch; NIL is the neutral element. AbutX builds from left to right, and AbutY from bottom to top.
AbutX: PROC [t1, t2, t3, t4, t5, t6: Object ← NIL] RETURNS [obj: Object];
AbutY: PROC [t1, t2, t3, t4, t5, t6: Object ← NIL] RETURNS [obj: Object];
AbutListX: PROC [listOb: ListOb] RETURNS [obj: Object];
AbutListY: PROC [listOb: ListOb] RETURNS [obj: Object];
-- AbutCheck: parse the pins and check if they match; stop and complain if pin mismatch
-- pins match if: same width (depth does not matter), same position, same layer, names checked by a special proc.
AbutCheckX: PROC [t1, t2, t3, t4, t5, t6: Object ← NIL] RETURNS [obj: Object];
AbutCheckY: PROC [t1, t2, t3, t4, t5, t6: Object ← NIL] RETURNS [obj: Object];
AbutCheckListX: PROC [listOb: ListOb] RETURNS [obj: Object];
AbutCheckListY: PROC [listOb: ListOb] RETURNS [obj: Object];
-- Arrays and other repetitions
-- MapFunction evaluates the function over the domain [lx..ux)*[ly..uy) and abuts the resulting tiles in an array. Creates empty cell when lx>=ux or ly>=uy.
XYFunction: TYPE = PROC [x, y: INT] RETURNS [resultingOb: Object];
MapFunctionX: PROC [function: XYFunction, lx: INT ← 0, ux: INT] RETURNS [new: Object];
MapFunctionY: PROC [function: XYFunction, ly: INT ← 0, uy: INT] RETURNS [new: Object];
MapFunction: PROC [function: XYFunction, lx: INT ← 0, ux: INT, ly: INT ← 0, uy: INT] RETURNS [new: Object];
MapFunctionIndexPins: PROC [function: XYFunction, lx: INT ← 0, ux: INT, ly: INT ← 0, uy: INT, indexedPins: ARRAY PWPins.Side OF LIST OF ROPEALL [NIL]] RETURNS [new: Object];
Does a map function and indexes at the same time pins which are in indexedPins. Other pins are propagated
-- Aligns nx tiles in the X (--) direction. If nx<=0 an empty cell is created
ArrayX: PROC [ob: Object, nx: INT ← 1] RETURNS [Object];
-- Aligns ny tiles in the Y (|) direction. If nx<=0 an empty cell is created
ArrayY: PROC [ob: Object, ny: INT ← 1] RETURNS [Object];
-- Equivalent to ArrayY[ArrayX[ob, nx], ny]: no flat 2D array
Array: PROC [ob: Object, nx, ny: INT ← 1] RETURNS [new: Object];
-- Planar tranformations and instance names: these properties are usually associated to instances, not objects, so we have to add an extra level of hierarchy
ChangeOrientation: PUBLIC PROC [obj: Object, orientation: CDOrient.Orientation] RETURNS [cell: Object];
-- Symmetry that changes X (so/Y)
FlipX: PROC [ob: Object] RETURNS [Object] =
INLINE {RETURN [ChangeOrientation[ob, CDOrient.mirrorX]]};
Symmetry that changes Y (so/X)
FlipY: PROC [ob: Object] RETURNS [Object] =
INLINE {RETURN [ChangeOrientation[ob, CDOrient.mirrorY]]};
Logically same as copy
Identity: PROC [ob: Object] RETURNS [Object] =
INLINE {RETURN [ob]};
Counter-clockwise
Rot90: PROC [ob: Object] RETURNS [Object] =
INLINE {RETURN [ChangeOrientation[ob, CDOrient.rotate90]]};
Rot180: PROC [ob: Object] RETURNS [Object] =
INLINE {RETURN [ChangeOrientation[ob, CDOrient.rotate180]]};
Rot270: PROC [ob: Object] RETURNS [Object] =
INLINE {RETURN [ChangeOrientation[ob, CDOrient.rotate270]]};
InstanceName: PROC [obj: Object, instanceName: ROPE] RETURNS [cell: Object];
-- Copy and conditional objects
-- Copy: first level only, i.e. any subcell is just referenced, not duplicated
Copy: PROC [ob: Object] RETURNS [new: Object];
-- Parametrized cells (conditional objects only for now)
Inst: PROC [ob: Object, conds: LIST OF ROPE, removeNamed: BOOLTRUE] RETURNS [new: Object];
-- Flattens the content of a cell one level only
Flatten: PROC [design: Design, cell: Object] RETURNS [new: Object];
FlattenOnce: PROC [design: Design, cell: Object] RETURNS [new: Object];
-- Designs, directories, . . .
Get creates a Indirect object that is a low-weight import. Provokes an ERROR if no such name in the directory.
Get: PROC [design: Design, name: ROPE] RETURNS [ob: Object];
-- Open a design, given a file name
OpenDesign: PROC [fileName: ROPE] RETURNS [design: Design];
Christian requires that!
CleanUp: PROC [design: Design] = INLINE {CDCleanUp.CleanUp[design]};
-- Registration of a new UserProc
Register: PROC [userProc: UserProc, name: ROPE];
You are on your own
This goodie is to register a property which is an ATOM (instead of a REF), when you do not care about registering it many times, and so that it is easy to specify the copy proc. If the argument flushOnEdit is set to TRUE, all edits of a cell will provoke the dismiss of the property for that cell and all the cells that depends on it.
RegisterProp: PROC [prop: ATOM, copy: BOOLFALSE, flushOnEdit: BOOLFALSE] RETURNS [sameAtom: ATOM];
-- Empty cell: must be repositionned and included in a directory when filled
CreateEmptyCell: PROC RETURNS [cell: Object] = INLINE {cell ← CDCells.CreateEmptyCell[]};
-- Include an object in a cell; position is relative to the InterestRect
IncludeInCell: PROC [cell: Object, obj: Object, position: CD.Position ← [0, 0], orientation: CDOrient.Orientation ← CD.original] RETURNS [newInst: Instance];
-- Adds the properties of obj which are copiable to the ones of newObj
AppendProps: PROC [newObj, obj: Object];
-- Reposition the object. Should be called for every cell created by CreateEmptyCell, once filled
RepositionCell: PROC [obj: Object] = INLINE {[] ← CDCells.RepositionCell[obj, NIL]};
-- The following primitive allows the use of the InterestRect coordinates only: location is the position of the InterestRect of inst in the InterestRect coordinate system of obj
GetLocation: PROC [inst: Instance, obj: Object] RETURNS [location: CD.Position];
-- Tries to find the property on the object, if it fails on the class, and if it fails expands (a failure in expansion provokes the return of NIL) and starts all over again.
Send: PROC [obj: Object, prop: ATOM] RETURNS [value: REFNIL, expandedObj: Object];
High-level constructors (safe if your procs are safe)
ForEachPinProc: TYPE = PROC [inst: Instance] RETURNS [obj: Object];
SelectNamesProc: TYPE = PROC [name: ROPE] RETURNS [keepIt: BOOL];
KeepAll: SelectNamesProc;
-- Transfer cell is a very Xerographic constructor: it first creates an empty cell: one dimension is the specified width, the other is the same as the side of the template; then it parses the side of the template, and for every pin it calls the objProc and sticks the resulting object in the cell so that it faces the pin; the object is rotated according to the side in use, and the right side corresponds to the original orientation
TransferCell: PUBLIC PROC [template: Object, objSide: PWPins.Side, width: INT, objProc: ForEachPinProc, selectNameProc: SelectNamesProc ← KeepAll] RETURNS [cell: Object];
-- put pins, make by rotation!!!
TopFillerCell: PROC [template: Object, height: INT, selectNameProc: SelectNamesProc ← KeepAll] RETURNS [cell: Object];
BottomFillerCell: PUBLIC PROC [template: Object, height: INT, selectNameProc: SelectNamesProc ← KeepAll] RETURNS [cell: Object];
LeftFillerCell: PROC [template: Object, width: INT, selectNameProc: SelectNamesProc ← KeepAll] RETURNS [cell: Object];
RightFillerCell: PUBLIC PROC [template: Object, width: INT, selectNameProc: SelectNamesProc ← KeepAll] RETURNS [cell: Object];
Tools for helping the designer debug his PW code
Draw: PROC [obj: CD.Object, technologyName: ATOMNIL] RETURNS [design: CD.Design];
Creates a new CD viewer and displays the object. Default is $CMos technology. The object and its depencies are NOT included in the design.
Goodies
-- Input and output from the terminal
WriteF: PROC [format: ROPENIL, v1, v2, v3, v4, v5: IO.Value ← [null[]]] = INLINE {TerminalIO.WriteF[format, v1, v2, v3, v4, v5]};
RequestRope: PROC [text: ROPENIL] RETURNS [ROPE] = INLINE {RETURN[TerminalIO.RequestRope[text]]};
RequestInt: PROC [text: ROPENIL] RETURNS [INT] = INLINE {RETURN[TerminalIO.RequestInt[text]]};
-- Predicates
ODD: PROC [i: INT] RETURNS [BOOL];
EVEN: PROC [i: INT] RETURNS [BOOL];
-- Dealing with Log2 of numbers
Log2: PROC [n: INT] RETURNS [INT];
TwoToThe: PROC [x: INT] RETURNS [INT];
TwoToTheLog2: PROC [n: INT] RETURNS [INT];
-- Extract the xth bit in the interger N
-- Warning: bit 0 is the LOW order bit (lsb). That is NOT the mesa convention!
XthBitOfN: PROC [x, n: INT] RETURNS [BOOL];
END.