PWImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reversed.
Created by: Monier, January 31, 1985 3:09:14 pm PST
Last Edited by: Serlet, May 10, 1985 9:52:05 am PDT
-- PW is a module generator using a subset of the Parquet operations.
DIRECTORY
Atom USING [GetProp, MakeAtom, PutProp],
CD USING [Design, ObPtr],
CDMenus USING [CreateEntry, CreateMenu, ImplementMenuCommand],
CDOps USING [AddAnObject],
CDOrient USING [Orientation],
CDSequencer USING [Command, CommandProc, ImplementCommand],
Commander USING [CommandObject, Handle],
CommandTool USING [DoCommandRope, Run],
IO USING [noInputStream, noWhereStream, RopeFromROS, ROS],
PW USING [ObjName, ROPE, UserProc, XYFunction],
PWBasics,
PWConditional,
PWLow,
Rope USING [Cat, Find, Substr],
SymTab USING [Create, Fetch, Ref, Store, Val],
TerminalIO USING [RequestRope];
PWImpl: CEDAR PROGRAM
IMPORTS Atom, CDMenus, CDOps, CDSequencer, CommandTool, IO, PWBasics, PWConditional, PWLow, Rope, SymTab, TerminalIO
EXPORTS PW =
BEGIN
OPEN PW;
-- Utilities for complex abuts
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]]};
*** The arithmetic stuff that people always want ***
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];
XthBitOfN: PUBLIC PROC [x, n: INT] RETURNS [BOOL] =
PWBasics.Output: bit 0 is the LOW order bit (lsb)
{RETURN [IF x<0 THEN FALSE ELSE (n/TwoToThe[x]) MOD 2 =1]};
-- Rotating cells
ChangeOrientation: PUBLIC PROC [dir: CDOrient.Orientation, tile: ObjName] RETURNS [ObjName] =
{RETURN [PWBasics.NameFromObj[PWLow.ChangeOrientation[design, ObjFromObjName[tile], dir]]]};
-- Parametrized cells (conditional objects)
Inst: PUBLIC PROC [name: ObjName, conds: LIST OF ROPE, removeNamed: BOOLTRUE] RETURNS [new: ObjName] =
{RETURN [
PWBasics.NameFromObj[
PWConditional.Inst[
design,
PWBasics.ObjFromName[design, name],
conds,
removeNamed]]]};
-- Private State Variables
-- Design on which we are working. Set by all CDSequencer.ImplementCommand
design: PRIVATE CD.Design;
-- Table of all registred generators
generators: PRIVATE SymTab.Ref ← SymTab.Create[];
-- Menu displayed by ChipNDale
menu: PRIVATE REF;
-- Abuts
ObjFromObjName: PROC [name: ObjName] RETURNS [CD.ObPtr] =
{index: INT = Rope.Find[name, ":"];
IF index=-1 THEN RETURN [PWBasics.ObjFromName[design, name]];
PWBasics.Output["Old way of naming instances:  '""", name, """'. The new, preferred way (and soon only way - yes, that's fascism) is:  'PW.ReName[""", Rope.Cat[Rope.Substr[name, index+1], """, """, Rope.Substr[name, 0, index], """]'.\n"]];
RETURN [PWLow.ReName[design,
PWBasics.ObjFromName[design, Rope.Substr[name, index+1]],
Rope.Substr[name, 0, index]]]};
ListObjFromObjNames: PROC [names: LIST OF ObjName] RETURNS [LIST OF CD.ObPtr] = {
revList, list: LIST OF CD.ObPtr ← NIL;
WHILE names#NIL DO
revList ← CONS[ObjFromObjName[names.first], revList];
names ← names.rest;
ENDLOOP;
WHILE revList#NIL DO
list ← CONS[revList.first, list];
revList ← revList.rest;
ENDLOOP;
RETURN[list];
};
AbutListX: PUBLIC PROC [subNames: LIST OF ObjName] RETURNS [new: ObjName] =
{RETURN [PWBasics.NameFromObj[
PWLow.AbutListX[design, ListObjFromObjNames[subNames]]]]};
AbutListY: PUBLIC PROC [subNames: LIST OF ObjName] RETURNS [new: ObjName] =
{RETURN [PWBasics.NameFromObj[
PWLow.AbutListY[design, ListObjFromObjNames[subNames]]]]};
Listify: PROC [t1, t2, t3, t4, t5, t6, t7, t8: ObjName ← NIL] RETURNS [list: LIST OF ObjName ← NIL] =
BEGIN
IF t8 # NIL THEN list ← CONS [t8, list];
IF t7 # NIL THEN list ← CONS [t7, list];
IF t6 # NIL THEN list ← CONS [t6, list];
IF t5 # NIL THEN list ← CONS [t5, list];
IF t4 # NIL THEN list ← CONS [t4, list];
IF t3 # NIL THEN list ← CONS [t3, list];
IF t2 # NIL THEN list ← CONS [t2, list];
IF t1 # NIL THEN list ← CONS [t1, list];
END;
AbutX: PUBLIC PROC [t1, t2, t3, t4, t5, t6, t7, t8: ObjName ← NIL] RETURNS [new: ObjName] =
BEGIN
RETURN [AbutListX[Listify[t1, t2, t3, t4, t5, t6, t7, t8]]];
END;
AbutY: PUBLIC PROC [t1, t2, t3, t4, t5, t6, t7, t8: ObjName ← NIL] RETURNS [new: ObjName] =
BEGIN
RETURN [AbutListY[Listify[t1, t2, t3, t4, t5, t6, t7, t8]]];
END;
-- Arrays
evaluates the function function over the domain [lx..ux)*[ly..uy) and abut the resulting tiles in an array. Creates empty cell when lx>=ux or ly>=uy.
MapFunction: PUBLIC PROC [function: XYFunction, lx: INT ← 0, ux: INT, ly: INT ← 0, uy: INT] RETURNS [new: ObjName]=
BEGIN  
rows: LIST OF ObjName ← NIL;
FOR y: INT DECREASING IN [ly .. uy) DO
row: LIST OF ObjName ← NIL;
FOR x: INT DECREASING IN [lx .. ux) DO -- make a row
row ← CONS [function[x, y], row];
ENDLOOP;
-- create the tile corresponding to the row
rows ← CONS [AbutListX[row], rows];
ENDLOOP;
-- create the tile corresponding to the set of rows
RETURN [AbutListY[rows]];
END;
ArrayX: PUBLIC PROC [objName: ObjName, nx: INT ← 1] RETURNS [new: ObjName] = {
new ← Array[objName, nx, 1];
};
ArrayY: PUBLIC PROC [objName: ObjName, ny: INT ← 1] RETURNS [new: ObjName] = {
new ← Array[objName, 1, ny];
};
Array: PUBLIC PROC [objName: ObjName, nx, ny: INT ← 1] RETURNS [new: ObjName] = {
Identity: XYFunction = {instName ← objName};
new ← MapFunction[function: Identity, lx: 0, ux: nx, ly: 0, uy: ny];
};
-- Registration of UserProc
Register: PUBLIC PROC [userProc: UserProc, name: ROPE] =
BEGIN
IF ~SymTab.Store[generators, name, NEW [UserProc ← userProc]]
THEN PWBasics.Output["Generator program ", name, " overwritten.\n"]
ELSE
BEGIN
atom: ATOM ← Atom.MakeAtom[Rope.Cat["PWGenerator-", name]];
CDSequencer.ImplementCommand[atom, RunGenerator];
Atom.PutProp[atom, "PWGenerator", name];
CDMenus.CreateEntry[menu, Rope.Cat["Run ", name, " generator"], atom];
PWBasics.Output["Generator program ", name, " recorded.\n"];
END;
END;
-- PW heart: these one really make abuts by calling the user proc.
RunGenerator: PROC [command: CDSequencer.Command] =
BEGIN
userProc: UserProc;
val: SymTab.Val;
found: BOOL;
result: ROPE;
name: ROPENARROW [Atom.GetProp[command.a, "PWGenerator"]];
[found: found, val: val]← SymTab.Fetch[generators, name];
IF ~found THEN {PWBasics.Output["PW Internal PWBasics.Error in RunGenerator. Contact implementor.\n"]; ERROR};
userProc ← NARROW [val, REF UserProc]^; -- explicit dereferencing
design ← command.design; -- we must set this variable!
result ← userProc[design];
result ← ReName[result, name];
CDOps.AddAnObject[design, PWBasics.ObjFromName[design, result], command.pos];
PWBasics.Output["PW execution done with cell ", result, ".\n"];
END;
CompileAndRun: PROC [command: CDSequencer.Command] =
BEGIN
name: ROPE ← TerminalIO.RequestRope["Name of the PW program : "];
errMsg: ROPE; error: BOOL;
handle: Commander.Handle ← NEW [Commander.CommandObject ← [in: IO.noInputStream, out: IO.noWhereStream, err: IO.ROS[]]];
result: REF ANY; out: ROPE;
PWBasics.Output["Compile ", name, " ...\n"];
[out, result] ← CommandTool.DoCommandRope[
commandLine: Rope.Cat["Compile ", name, "\n"], parent: handle];
PWBasics.Output[out, IO.RopeFromROS[handle.err], "\n"];
PWBasics.Output["Run ", name, " ...\n"];
[errMsg: errMsg, error: error] ← CommandTool.Run[name];
IF error THEN {PWBasics.Output[errMsg]; ERROR};
END;
FlushCaches: PROC [command: CDSequencer.Command] =
BEGIN
design ← command.design; -- we must set this variable!
PWLow.FlushCaches[design];
END;
-- Other functions
Naming instances
ReName: PUBLIC PROC [oldName: ObjName, instanceName: ROPE] RETURNS [newCellName: ObjName] = {
newCellName ← PWBasics.NameFromObj[
PWLow.ReName[design, PWBasics.ObjFromName[design, oldName], instanceName]];
};
Making objects non stretchable
MakeObjNonStretchable: PUBLIC PROC [objName: ObjName] = {
PWLow.MakeObjNonStretchable[PWBasics.ObjFromName[design, objName]];
};
-- main program
-- register menu
menu ← CDMenus.CreateMenu["Patchwork user menu", $PatchworkUserMenu];
CDMenus.ImplementMenuCommand[$PatchworkUserMenu, menu];
register compile-and-run and others entries
CDSequencer.ImplementCommand[$CompileAndRun, CompileAndRun];
CDSequencer.ImplementCommand[$FlushCaches, FlushCaches];
CDMenus.CreateEntry[menu, "Compile and run a PW program", $CompileAndRun];
CDMenus.CreateEntry[menu, "Flush all hidden caches", $FlushCaches];
END.