[Indigo]<Rosemary>2.6>Rosemary.df=>RoseCaptureImpl.Mesa
Last Edited by: Spreitzer, December 2, 1984 5:21:16 pm PST
DIRECTORY Asserting, AssertingIO, Convert, FS, GetMe, IO, OrderedSymbolTableRef, PupDefs, Rope, RoseCapture, RoseCreate, RoseTypes, UserCredentials;
RoseCaptureImpl: CEDAR PROGRAM
IMPORTS Asserting, AssertingIO, Convert, FS, GetMe, IO, OrderedSymbolTableRef, PupDefs, Rope, RoseCreate, RoseTypes, UserCredentials
EXPORTS RoseCapture =
BEGIN OPEN RoseTypes;
LORA: TYPE = LIST OF REF ANY;
DesignCapture: TYPE = REF DesignCaptureRep;
DesignCaptureRep: TYPE = RECORD [
fileNameRoot: ROPE,
dfOut: STREAM,
genCount: INT ← 0
];
CTCapture: TYPE = REF CTCaptureRep;
CTCaptureRep: TYPE = RECORD [
dc: DesignCapture,
cellOut: STREAM,
cell: Cell
];
Wire: TYPE = REF WireRep;
WireRep: TYPE = RECORD [name: ROPE, better: Wire ← NIL, worse: WireList ← NIL];
WireList: TYPE = LIST OF Wire;
machineName: ROPE ← "??";
userName: ROPE ← "??";
capKey: ATOM ← $Capture;
wireKey: ATOM ← $Wire;
captureExpansion: ERClass ← NEW [ERClassRep ← [
CellInstance: CellInstance,
NodeInstance: NodeInstance,
SplitJoin: SplitJoin,
ChangeReps: ChangeReps]];
Log: PROC [format: ROPE, v1, v2, v3, v4, v5: IO.Value ← [null[]]] =
BEGIN
msg: ROPEIO.PutFR[format, v1, v2, v3, v4, v5];
SIGNAL Warning[msg];
END;
CaptureDesign: PUBLIC PROC [directory, fileNameRoot, topCellTypeName: ROPE] =
BEGIN
dfName: ROPE ← fileNameRoot.Cat["-Str.DF"];
dc: DesignCapture ← NEW [DesignCaptureRep ← [fileNameRoot, FS.StreamOpen[dfName, create]]];
topCellType: CellType ← RoseCreate.GetCellType[topCellTypeName];
IF topCellType = NIL THEN {Log["No such cell type as %g", IO.refAny[topCellTypeName]]; RETURN};
machineName ← PupDefs.GetMyName[];
userName ← UserCredentials.Get[].name;
dc.dfOut.PutF["-- (Design %g)\n", IO.refAny[dfName]];
dc.dfOut.PutF["-- (CreatingUser %g)\n", IO.refAny[userName]];
dc.dfOut.PutF["-- (CreationTime \"%g\")\n", IO.time[]];
dc.dfOut.PutF["-- (CreationSite \"MilkyWay Sol III USA Xerox PARC ComputerResearch %q\")\n", IO.rope[machineName]];
dc.dfOut.PutF["-- (DerivingProgram \"Rosemary Structure Capturer\" %g)\n", IO.refAny[GetMe.StandardScrewyEncoding[GetMe.GetVersion[]]]];
dc.dfOut.PutF["\n\nDirectory %g\n %g\n", IO.rope[directory], IO.rope[dfName]];
CaptureCellType[
dc,
NEW [CellRep ← [
name: "Root",
type: topCellType,
parent: NIL,
internalNodes: OrderedSymbolTableRef.CreateTable[ RoseCreate.CompareNodes],
components: OrderedSymbolTableRef.CreateTable[ RoseCreate.CompareComponents],
interfaceNodes: NEW [NodeSR[0]],
substantiality: Real,
expansion: Nested
]]
];
dc.dfOut.Close[];
END;
CaptureCellType: PROC [dc: DesignCapture, cell: Cell] =
BEGIN
WriteNode: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
WriteAliases: PROC [worse: WireList] = {
FOR worse ← worse, worse.rest WHILE worse # NIL DO
ctc.cellOut.PutF[" (%g (G P))", IO.refAny[worse.first.name]];
WriteAliases[worse.first.worse];
ENDLOOP};
WriteWires: PROC [type: NodeType, ra: REF ANY, other: Assertions] = {
WITH type SELECT FROM
ant: ArrayNodeType => {list: LORANARROW[ra];
FOR i: INT IN [ant.first .. ant.last] DO
WriteWires[ant.element, list.first, other]; list ← list.rest;
ENDLOOP};
ant: AtomNodeType => {w: Wire ← NARROW[ra];
IF w.better = NIL THEN {
ctc.cellOut.PutF["(N %g (G D)", IO.refAny[w.name]];
IF w.worse # NIL THEN {
ctc.cellOut.PutRope[" (A"];
WriteAliases[w.worse];
ctc.cellOut.PutRope[")"]};
FOR ol: Assertions ← other, ol.rest WHILE ol # NIL DO
ctc.cellOut.PutRope[" "];
AssertingIO.WriteAssn[ctc.cellOut, ol.first];
ENDLOOP;
ctc.cellOut.PutRope[")\n"];
};
};
ENDCASE => ERROR};
n: Node ← NARROW[ra];
w: REF ANY ← Asserting.FnVal[fn: wireKey, from: n.other];
stop ← FALSE;
WriteWires[n.type, w, Asserting.AssertionsNotAbout[reln: wireKey, from: n.other]];
};
DestroyNode: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
n: Node ← NARROW[ra];
stop ← FALSE;
IF cell.internalNodes.Delete[n] # n THEN ERROR;
n.type ← NIL;
n.data ← NIL;
n.initialValue ← NIL;
n.cellIn ← NIL;
n.visible ← [NIL, LAST[CARDINAL]];
n.connections ← NIL;
n.nextPerturbed ← notInNodeList;
IF n.nextAffected # notInNodeList OR n.nextX # notInNodeList OR n.prevX # notInNodeList THEN ERROR;
n.watchers ← ALL[NIL];
n.next ← NIL;
n.other ← NIL;
};
WriteComponent: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
WriteConnection: PROC [type: NodeType, portName: ROPE, ra: REF ANY] =
{WITH type SELECT FROM
ant: ArrayNodeType => {list: LORANARROW[ra];
FOR i: INTEGER IN [ant.first .. ant.last] DO
WriteConnection[ant.element, Sub[portName, i], list.first];
list ← list.rest;
ENDLOOP};
ant: AtomNodeType => {w: Wire ← Best[ra];
ctc.cellOut.PutF["\n\t\t(%g %g)", IO.refAny[portName], IO.refAny[w.name]];
};
ENDCASE => ERROR};
c: Cell ← NARROW[ra];
prev: Cell ← NIL;
stop ← FALSE;
ctc.cellOut.PutF["(CI %g %g (G D)\n\t(CIC", IO.refAny[c.name], IO.refAny[c.type.name]];
FOR index: CARDINAL IN [0 .. c.type.ports.length) DO
w: REF ANY← Asserting.FnVal[fn: wireKey, from: c.interfaceNodes[index].other];
WriteConnection[c.type.ports[index].type, c.type.ports[index].name, w];
ENDLOOP;
ctc.cellOut.PutRope[")"];
FOR ol: Assertions ← c.other, ol.rest WHILE ol # NIL DO
ctc.cellOut.PutRope["\n\t"];
AssertingIO.WriteAssn[ctc.cellOut, ol.first];
ENDLOOP;
ctc.cellOut.PutRope[")\n"];
SELECT Asserting.FnVal[fn: capKey, from: c.type.other] FROM
ctc.dc => NULL;
ENDCASE => CaptureCellType[ctc.dc, c];
IF cell.components.Delete[c] # c THEN ERROR;
IF c.realCellStuff # NIL THEN ERROR;
c.other ← NIL;
c.interfaceNodes ← NIL;
c.internalNodes.DestroyTable[];
c.components.DestroyTable[];
c.internalNodes ← c.components ← NIL;
IF c.firstInternalNode # NIL THEN ERROR;
IF c.leftChild # NIL THEN ERROR;
c.parent ← c.rightSibling ← NIL;
c.sim ← NIL;
c.nextInstance ← NIL;
c.type ← NIL;
};
cellFileName: ROPE ← CellFileName[dc, cell];
ctc: CTCapture ← NEW [CTCaptureRep ← [
dc: dc,
cellOut: FS.StreamOpen[cellFileName, create],
cell: cell
]];
insides: Structure;
cell.type.other ← Asserting.AssertFn1[fn: capKey, val: dc, inAdditionTo: cell.type.other];
dc.dfOut.PutF["\n-- (CellType %g)\n %g\n", IO.refAny[cell.type.name], IO.rope[cellFileName]];
ctc.cellOut.PutF["(CellTypeName %g)\n", IO.refAny[cell.type.name]];
ctc.cellOut.PutF["(CreationTime \"%g\")\n", IO.time[]];
ctc.cellOut.PutF["(CreatingUser %g)\n", IO.refAny[userName]];
ctc.cellOut.PutF["(CreationSite \"MilkyWay Sol III USA Xerox PARC ComputerResearch %q\")\n", IO.rope[machineName]];
ctc.cellOut.PutF["(DerivingProgram \"Rosemary Structure Capturer\" %g)\n", IO.refAny[GetMe.StandardScrewyEncoding[GetMe.GetVersion[]]]];
WritePorts[cell.type, ctc.cellOut];
WriteAssertions[cell.type.other, ctc.cellOut];
ctc.cellOut.PutRope["(PrivateFollows)\n"];
IF cell.type.expand # NIL
THEN {
cell.realCellStuff ← NEW [RealCellStuffRep ← [
schedNext: notInCellList,
nextNeeded: notInCellList,
nextNoted: notInCellList,
newIOAsWP: NIL,
oldIOAsWP: NIL,
switchIOAsWP: NIL,
state: insides ← NEW [StructureRep ← [
container: cell,
mirror: NEW [CellRep ← [
name: " world ",
type: cell.type,
parent: cell,
internalNodes: NIL,
components: NIL,
interfaceNodes: NEW [NodeSR[cell.type.ports.length]],
substantiality: Real,
expansion: Nested,
realCellStuff: NIL]],
insideNodes: NIL,
nextPerturbed: notInStrList,
nextWasPerturbed: notInStrList
]]
]];
insides.insideNodes ← insides.mirror.interfaceNodes;
FOR pi: NAT IN [0 .. cell.type.ports.length) DO
insideNode: Node ← NodeInstance[erInstance: ctc, name: cell.type.ports[pi].name, type: cell.type.ports[pi].type];
insides.insideNodes[pi] ← insideNode;
ENDLOOP;
cell.type.expand[ctc.cell, [ctc, captureExpansion]];
cell.internalNodes.EnumerateIncreasing[WriteNode];
WritePortNets[cell.type, ctc.cellOut, insides.insideNodes];
cell.components.EnumerateIncreasing[WriteComponent];
cell.realCellStuff.state ← NIL;
cell.realCellStuff ← NIL;
insides.mirror.parent ← NIL;
insides.mirror.type ← NIL;
insides.mirror.interfaceNodes ← NIL;
insides.mirror ← NIL;
cell.internalNodes.EnumerateIncreasing[DestroyNode];
}
ELSE ctc.cellOut.PutRope["(InsidesUnspecified)\n"];
ctc.cellOut.Close[];
END;
CellFileName: PROC [dc: DesignCapture, cell: Cell] RETURNS [cellFileName: ROPE] = {
fullCellFileName: ROPE;
cp: FS.ComponentPositions;
cellFileName ← NIL;
[fullCellFileName, cp, ] ← FS.ExpandName[cell.type.name !FS.Error => CONTINUE];
IF fullCellFileName # NIL AND fullCellFileName.Substr[start: cp.base.start, len: cp.base.length].Equal[cell.type.name] THEN RETURN [cell.type.name.Cat[".sch"]];
cellFileName ← IO.PutFR["%g-%g.sch", IO.rope[dc.fileNameRoot], IO.card[dc.genCount ← dc.genCount + 1]];
};
WriteAssertions: PROC [assertions: Assertions, to: IO.STREAM] =
BEGIN
FOR assertions ← assertions, assertions.rest WHILE assertions # NIL DO
AssertingIO.WriteAssn[to: to, assertion: assertions.first];
to.PutRope["\n"];
WITH assertions.first.first SELECT FROM
a: ATOM => SELECT a FROM
$Capture => LOOP;
ENDCASE;
ENDCASE => ERROR;
to.PutF["%g\n", IO.refAny[assertions.first]];
ENDLOOP;
END;
WritePorts: PROC [ct: CellType, to: IO.STREAM] =
BEGIN
dir: ROPE;
other: Assertions;
WritePort: PROC [type: NodeType, portName, ecName: ROPE] = {
WITH type SELECT FROM
ant: ArrayNodeType => {
IF ecName # NIL THEN Log["undoable equivalence class (%g) for port %g of cell type %g", IO.refAny[ecName], IO.refAny[portName], IO.refAny[ct.name]];
FOR i: INTEGER IN [ant.first .. ant.last] DO
WritePort[ant.element, Sub[portName, i], NIL];
ENDLOOP};
ant: AtomNodeType => {
to.PutF["\n\t(%g (G D) (%g)", IO.refAny[portName], IO.rope[dir]];
IF (ecName # NIL) AND (NOT ecName.Equal[portName]) THEN to.PutF[" (EC \"Structure\" %g)", IO.refAny[ecName]];
FOR al: Assertions ← other, al.rest WHILE al # NIL DO
to.PutChar[' ];
AssertingIO.WriteAssn[to, al.first];
ENDLOOP;
to.PutRope[")"];
};
ENDCASE => ERROR};
to.PutRope["(Ports"];
FOR pi: CARDINAL IN [0 .. ct.ports.length) DO
ec: ROPENARROW[Asserting.FnVal[$EC, ct.ports[pi].other, LIST[NARROW["Structure", ROPE]]]];
dir ← IF ct.ports[pi].input THEN (IF ct.ports[pi].output THEN "BIDIR" ELSE "IN") ELSE IF ct.ports[pi].output THEN "OUT" ELSE ERROR;
other ← Asserting.AssertionsNotAbout[$EC, ct.ports[pi].other];
WritePort[ct.ports[pi].type, ct.ports[pi].name, ec];
ENDLOOP;
to.PutRope[")\n"];
END;
WritePortNets: PROC [ct: CellType, to: IO.STREAM, insideNodes: NodeS] =
BEGIN
WritePortNet: PROC [type: NodeType, portName: ROPE, node: REF ANY] = {
WITH type SELECT FROM
ant: ArrayNodeType => {l: LORANARROW[node];
FOR i: INTEGER IN [ant.first .. ant.last] DO
WritePortNet[ant.element, Sub[portName, i], l.first];
l ← l.rest;
ENDLOOP;
IF l # NIL THEN ERROR};
ant: AtomNodeType => to.PutF["(PN %g %g)\n", IO.refAny[portName], IO.refAny[Best[node].name]];
ENDCASE => ERROR};
FOR pi: CARDINAL IN [0 .. ct.ports.length) DO
WritePortNet[ct.ports[pi].type,
ct.ports[pi].name,
Asserting.FnVal[fn: wireKey, from: insideNodes[pi].other]];
ENDLOOP;
END;
NodeInstance: PROC [erInstance: REF ANY, name: ROPE, type: NodeType, initialValue: ROPENIL, initData: REF ANYNIL, other: Assertions ← NIL] RETURNS [node: Node] =
BEGIN
ctc: CTCapture ← NARROW[erInstance];
node ← NEW [NodeRep ← [
name: name,
type: type,
initialValue: initialValue,
cellIn: ctc.cell,
nextPerturbed: notInNodeList,
nextAffected: notInNodeList,
nextX: notInNodeList,
prevX: notInNodeList,
other: other]];
ctc.cell.internalNodes.Insert[node !OrderedSymbolTableRef.DuplicateKey => {Log["Duplicated Node name: %g", IO.rope[name]]; CONTINUE}];
node.other ← Asserting.AssertFn1[fn: wireKey, val: CreateWires[type, name], inAdditionTo: node.other];
END;
CreateWires: PROC [type: NodeType, name: ROPE] RETURNS [ra: REF ANY] =
BEGIN
WITH type SELECT FROM
ant: ArrayNodeType => {
list: LORANIL;
FOR i: INTEGER DECREASING IN [ant.first .. ant.last] DO
list ← CONS[CreateWires[ant.element, Sub[name, i]], list];
ENDLOOP;
ra ← list};
ant: AtomNodeType =>
ra ← NEW [WireRep ← [name: name]];
ENDCASE => ERROR
END;
CellInstance: PROC [erInstance: REF ANY, instanceName, typeName, interfaceNodes: ROPE, other: Assertions ← NIL] RETURNS [cell: Cell] =
BEGIN
ctc: CTCapture ← NARROW[erInstance];
type: CellType ← RoseCreate.GetCellType[typeName];
IF type = NIL
THEN Log["No such cell type as %g", IO.refAny[typeName]]
ELSE {
cell ← NEW [CellRep ← [
name: instanceName,
type: type,
parent: ctc.cell,
internalNodes: OrderedSymbolTableRef.CreateTable[ RoseCreate.CompareNodes],
components: OrderedSymbolTableRef.CreateTable[ RoseCreate.CompareComponents],
interfaceNodes: NEW [NodeSR[type.ports.length]],
substantiality: Real,
expansion: Nested,
other: other
]];
RoseCreate.FillInInterfaceNodes[cell, interfaceNodes];
ctc.cell.components.Insert[cell !OrderedSymbolTableRef.DuplicateKey => {Log["Duplicated Cell name: %g", IO.rope[instanceName]]; CONTINUE}];
};
END;
SplitJoin: PROC [erInstance: REF ANY, a, b: StretchList, writeA, writeB: BOOLEAN] =
BEGIN
aWires: LIST OF TypedWire ← Squash[a];
bWires: LIST OF TypedWire ← Squash[b];
IF (a = NIL) # (b = NIL) THEN ERROR;
IF a = NIL THEN RETURN;
DO
IF (aWires = NIL) # (bWires = NIL) THEN ERROR;
IF aWires = NIL THEN EXIT;
ChangeWires[aWires.first, bWires.first];
aWires ← aWires.rest;
bWires ← bWires.rest;
ENDLOOP;
END;
TypedWire: TYPE = RECORD [type: NodeType, ra: REF ANY];
Squash: PROC [sl: StretchList] RETURNS [wl: LIST OF TypedWire] =
BEGIN
SquashWork: PROC [nt: NodeType, ra: REF ANY] = {
WITH nt SELECT FROM
ant: AtomNodeType => {
w: Wire ← NARROW[ra];
wl ← CONS[[ant, w], wl]};
ant: ArrayNodeType => {
l: LORANARROW[ra];
FOR i: INTEGER IN [ant.first .. ant.last] DO
SquashWork[ant.element, l.first];
l ← l.rest;
ENDLOOP;
IF l # NIL THEN ERROR};
ENDCASE => ERROR;
wl ← wl};
wl ← NIL;
FOR sl ← sl, sl.rest WHILE sl # NIL DO
ra: REF ANY ← Asserting.FnVal[fn: wireKey, from: sl.first.node.other];
WITH sl.first SELECT FROM
ss: SingleStretch => SquashWork[ss.node.type, ra];
ss: SubStretch => {
l: LORANARROW[ra];
ant: ArrayNodeType ← NARROW[ss.node.type];
FOR i: INTEGER IN [ant.first .. ant.last] DO
IF i IN [ss.first .. ss.last] THEN SquashWork[ant.element, l.first];
l ← l.rest;
ENDLOOP;
IF l # NIL THEN ERROR;
};
ENDCASE => ERROR;
ENDLOOP;
END;
ChangeReps: PROC [erInstance: REF ANY, a, b: Node, writeA, writeB: BOOLEAN] =
BEGIN
wa: REF ANY ← Asserting.FnVal[fn: wireKey, from: a.other];
wb: REF ANY ← Asserting.FnVal[fn: wireKey, from: b.other];
ChangeWires[[a.type, wa], [b.type, wb]];
END;
ChangeWires: PROC [a, b: TypedWire] =
{WITH a.type SELECT FROM
ant: ArrayNodeType => {bnt: ArrayNodeType ← NARROW[b.type];
aList: LORANARROW[a.ra];
bList: LORANARROW[b.ra];
IF ant.first # bnt.first OR ant.last # bnt.last THEN ERROR;
FOR i: INTEGER IN [ant.first .. ant.last] DO
ChangeWires[[ant.element, aList.first], [bnt.element, bList.first]];
aList ← aList.rest; bList ← bList.rest;
ENDLOOP};
ant: AtomNodeType => {bnt: AtomNodeType ← NARROW[b.type];
wa: Wire ← Best[a.ra];
wb: Wire ← Best[b.ra];
IF wa # wb
THEN {wb.better ← wa; wa.worse ← CONS[wb, wa.worse]}
ELSE ERROR;
};
ENDCASE => ERROR};
Best: PROC [ra: REF ANY] RETURNS [w: Wire] = {w ← NARROW[ra];
WHILE w.better # NIL DO w ← w.better ENDLOOP};
Sub: PROC [name: ROPE, i: INTEGER] RETURNS [s: ROPE] = {
s ← name.Cat["[", Convert.RopeFromInt[i], "]"]};
Setup: PROC = {
AssertingIO.SetWriter[$Capture, AssertingIO.DontWrite];
};
Setup[];
END.