[Indigo]<Rosemary>3.0>Rosemary.df=>RoseCaptureImpl.Mesa
Last Edited by: Spreitzer, July 12, 1985 4:09:48 pm PDT
DIRECTORY Asserting, AssertingIO, Convert, FS, GetMe, IO, PupDefs, RedBlackTree, RedBlackTreeExtras, Rope, RoseCapture, RoseCreate, RoseTypes, UserCredentials;
RoseCaptureImpl: CEDAR PROGRAM
IMPORTS Asserting, AssertingIO, Convert, FS, GetMe, IO, PupDefs, RedBlackTree, RedBlackTreeExtras, 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,
Equivalence: Equivalence
]];
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, designName, topCellTypeName: ROPE] =
BEGIN
fileNameRoot: ROPE ← designName;
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["-- (DesignName %g)\n", IO.refAny[designName]];
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, topCellType];
dc.dfOut.Close[];
END;
CaptureCellType: PROC [dc: DesignCapture, cellType: CellType] =
BEGIN
cell: Cell ← NEW [CellRep ← [
name: Rope.Cat["An instance of ", cellType.name, ", which is being captured"],
type: cellType,
parent: NIL,
internalNodes: RedBlackTree.Create[RoseCreate.GetNodeKey, RoseCreate.CompareNodes],
components: RedBlackTree.Create[RoseCreate.GetComponentKey, RoseCreate.CompareComponents],
interfaceNodes: NEW [NodeSR[cellType.ports.length]],
substantiality: Shadow,
expansion: Expand
]];
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 [0 .. ant.length) 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.Filter[reln: wireKey, from: n.other].notAbout];
};
DestroyNode: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
n: Node ← NARROW[ra];
stop ← FALSE;
IF cell.internalNodes.Delete[n.name].data # n THEN ERROR;
n.type ← NIL;
n.cellIn ← NIL;
IF n.nextPerturbed # notInNodeList OR n.nextAffected # notInNodeList OR n.nextDelayed # notInNodeList OR n.prevDelayed # notInNodeList THEN ERROR;
n.watchers ← ALL[NIL];
n.designNext ← 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 [0 .. ant.length) 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.type];
IF cell.components.Delete[c.name].data # 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 ← CellTypeFileName[dc, cellType];
ctc: CTCapture ← NEW [CTCaptureRep ← [
dc: dc,
cellOut: FS.StreamOpen[cellFileName, create],
cell: cell
]];
cellType.other ← Asserting.AssertFn1[fn: capKey, val: dc, inAdditionTo: cellType.other];
dc.dfOut.PutF["\n-- (CellType %g)\n %g\n", IO.refAny[cellType.name], IO.rope[cellFileName]];
ctc.cellOut.PutF["(CellTypeName %g)\n", IO.refAny[cellType.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[cellType, ctc.cellOut];
WriteAssertions[cellType.other, ctc.cellOut];
ctc.cellOut.PutRope["(PrivateFollows)\n"];
IF cellType.expand # NIL
THEN {
FOR pi: PortIndex IN [0 .. cellType.ports.length) DO
port: Port ← cellType.ports[pi];
cell.interfaceNodes[pi] ← captureExpansion.NodeInstance[ctc, port.name, port.type];
ENDLOOP;
cellType.expand[ctc.cell, [ctc, captureExpansion]];
cell.internalNodes.EnumerateIncreasing[WriteNode];
WritePortNets[cellType, ctc.cellOut, cell.interfaceNodes];
RedBlackTreeExtras.StatelessEnumerateIncreasing[cell.components, WriteComponent, RoseCreate.GetComponentKey];
RedBlackTreeExtras.StatelessEnumerateIncreasing[cell.internalNodes, DestroyNode, RoseCreate.GetNodeKey];
}
ELSE ctc.cellOut.PutRope["(InsidesUnspecified)\n"];
ctc.cellOut.Close[];
END;
CellTypeFileName: PROC [dc: DesignCapture, cellType: CellType] RETURNS [cellFileName: ROPE] = {
fullCellFileName: ROPE;
cp: FS.ComponentPositions;
cellFileName ← NIL;
[fullCellFileName, cp, ] ← FS.ExpandName[cellType.name !FS.Error => CONTINUE];
IF fullCellFileName # NIL AND fullCellFileName.Substr[start: cp.base.start, len: cp.base.length].Equal[cellType.name] THEN RETURN [cellType.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 [0 .. ant.length) 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.Filter[$EC, ct.ports[pi].other].notAbout;
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 [0 .. ant.length) 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, initialValueFormat: ROPENIL, initData: REF ANYNIL, other: Assertions ← NIL] RETURNS [node: Node] =
BEGIN
ctc: CTCapture ← NARROW[erInstance];
node ← NEW [NodeRep ← [
name: name,
type: type,
cellIn: ctc.cell,
nextPerturbed: notInNodeList,
nextAffected: notInNodeList,
nextDelayed: notInNodeList,
prevDelayed: notInNodeList,
significances: designOnly,
other: other]];
ctc.cell.internalNodes.Insert[node, node.name !RedBlackTree.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 [0 .. ant.length) 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: RedBlackTree.Create[RoseCreate.GetNodeKey, RoseCreate.CompareNodes],
components: RedBlackTree.Create[RoseCreate.GetComponentKey, RoseCreate.CompareComponents],
interfaceNodes: NEW [NodeSR[type.ports.length]],
substantiality: Shadow,
expansion: Expand,
other: other
]];
RoseCreate.FillInInterfaceNodes[cell, interfaceNodes];
ctc.cell.components.Insert[cell, cell.name !RedBlackTree.DuplicateKey => {Log["Duplicated Cell name: %g", IO.rope[instanceName]]; CONTINUE}];
};
END;
Equivalence: PROC [erInstance: REF ANY, a, b: NodeExpression] =
BEGIN
aWires: LORA ← Flatten[[NIL, NIL], a].head;
bWires: LORA ← Flatten[[NIL, NIL], b].head;
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;
MergeWires[aWires.first, bWires.first];
aWires ← aWires.rest;
bWires ← bWires.rest;
ENDLOOP;
END;
TList: TYPE = RECORD [head, tail: LORA];
Flatten: PROC [prefix: TList, ne: NodeExpression] RETURNS [wtl: TList] = {
WITH ne SELECT FROM
x: PrimaryNE => {
wl: LORA ← GetNodeWires[x.node];
wtl ← TLCat[prefix, WLSelect[wl, x.selector]];
};
x: UnnamedConsNE => {
wtl ← prefix;
FOR elts: LIST OF PrimaryNE ← x.elts, elts.rest WHILE elts # NIL DO
wtl ← Flatten[wtl, elts.first];
ENDLOOP;
};
x: CatenateNE => {
wtl ← prefix;
FOR pieces: LIST OF NodeExpression ← x.pieces, pieces.rest WHILE pieces # NIL DO
wtl ← Flatten[wtl, pieces.first];
ENDLOOP;
};
ENDCASE => ERROR;
};
GetNodeWires: PROC [n: Node] RETURNS [wl: LORA] = {
ra: REF ANY ← Asserting.FnVal[fn: wireKey, from: n.other];
WITH ra SELECT FROM
w: Wire => RETURN [LIST[w]];
x: LORA => RETURN [x];
ENDCASE => ERROR;
};
WLSelect: PROC [wl: LORA, s: Selector] RETURNS [wtl: TList] = {
WITH s SELECT FROM
whole => {
wtl ← [NIL, NIL];
FOR wl ← wl, wl.rest WHILE wl # NIL DO
wtl ← TLAppend[wtl, wl.first];
ENDLOOP;
};
number => {
FOR i: INT IN [0 .. index) DO
wl ← wl.rest;
ENDLOOP;
wl ← LIST[wl.first];
wtl ← [wl, wl];
};
range => {
min, max: INT;
IF up
THEN {min ← first; max ← first + count - 1}
ELSE {min ← first + 1 - count; max ← first};
FOR i: INT IN [0 .. min) DO wl ← wl.rest ENDLOOP;
wtl ← [NIL, NIL];
FOR i: INT IN [min .. max) DO
wtl ← TLAppend[wtl, wl.first];
wl ← wl.rest;
ENDLOOP;
};
ENDCASE => ERROR;
};
TLAppend: PROC [wtl: TList, r: REF ANY] RETURNS [wul: TList] = {
this: LORALIST[r];
wul ← wtl;
IF wul.tail # NIL THEN wul.tail.rest ← this ELSE wul.head ← this;
wul.tail ← this;
};
TLCat: PROC [a, b: TList] RETURNS [c: TList] = {
IF a = [NIL, NIL] THEN RETURN [b];
IF b = [NIL, NIL] THEN RETURN [a];
c ← [a.head, b.tail];
a.tail.rest ← b.head;
};
MergeWires: PROC [a, b: REF ANY] = {
wa: Wire ← Best[a];
wb: Wire ← Best[b];
IF wa # wb
THEN {wb.better ← wa; wa.worse ← CONS[wb, wa.worse]}
ELSE 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[capKey, AssertingIO.DontWrite];
};
Setup[];
END.