JasmineThymeImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Created by Neil Gunther; June 25, 1986 5:42:11 pm PDT
Last Edited by: Neil Gunther July 24, 1986 5:32:38 pm PDT
DIRECTORY
Convert USING [RopeFromInt, RopeFromReal],
IO USING [PutR, time],
Jasmine,
JasmineThyme,
Rope USING [Cat, Concat, Equal, Length, Match, ROPE, Substr],
spMain USING [NormalRun],
spGlobals USING [Handle, MakeThymeViewers],
SymTab USING [Fetch, Ref],
TiogaFileOps USING [CreateRoot, InsertAsLastChild, Ref, SetContents, SetStyle, Store],
ViewerTools USING [SetContents];
JasmineThymeImpl: CEDAR PROGRAM
IMPORTS Convert, IO, Jasmine, Rope, spMain, spGlobals, SymTab, TiogaFileOps, ViewerTools
EXPORTS JasmineThyme
= BEGIN
TNode: TYPE = TiogaFileOps.Ref;
lastNode: Rope.ROPE;
driveNode: Rope.ROPE ← "driveInput";
Element: TYPE = {contact, transistor, wire};
Error: SIGNAL [msg: Rope.ROPE] = CODE;
CreateThymeFile: PUBLIC PROC [jasmineModel: SymTab.Ref, outputFile: Rope.ROPE] = {
root: TNode ← TiogaFileOps.CreateRoot[];
IF NOT Rope.Match[pattern: "*.thy", object: outputFile, case: FALSE] THEN outputFile ← Rope.Concat[outputFile, ".thy"];
PrintHeader[root, outputFile];
PrintCircuit[root, jasmineModel, outputFile];
TiogaFileOps.Store[root, outputFile]
};
PrintHeader: PROC [root: TNode, outputFile: Rope.ROPE] = {
node: TNode;
subNode: TNode;
TiogaFileOps.SetStyle[root, "Cedar"];
node ← TiogaFileOps.InsertAsLastChild[root];
TiogaFileOps.SetContents[node, Rope.Cat["--", outputFile, "\t\tCreated by Jasmine on ", IO.PutR[IO.time[]]]];
subNode ← TiogaFileOps.InsertAsLastChild[root];
TiogaFileOps.SetContents[subNode, Rope.Cat["--", "Feature resolution: ", SELECT Jasmine.resolution FROM high=>"high", medium=>"medium", ENDCASE=>"low"]];
[] ← TiogaFileOps.InsertAsLastChild[root];
};
PrintCircuit: PROC [root: TNode, model: SymTab.Ref, outputFile: Rope.ROPE] = {
tNode: TNode ← TiogaFileOps.InsertAsLastChild[root];
tSubNode: TNode;
plotControl: Rope.ROPE;
TiogaFileOps.SetContents[tNode, "CIRCUIT[Lambda ← 1, TDegC ← 25] = {"];
tSubNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[tSubNode, "Vdd: Node;"];
tSubNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[tSubNode, "! /DATools/DATools6.1/Thyme/SignalGenerators.thy"];
tSubNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[tSubNode, "! /DATools/DATools6.1/Thyme/BSim.thy"];
tSubNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[tSubNode, "! /DATools/DATools6.1/Jasmine/Jasmine.thy\n"];
tSubNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[tSubNode, "powerSupply: Voltage[Vdd, Gnd] = 5.0;"];
PrintInstanceNodes[root, model];
tNode ← TiogaFileOps.InsertAsLastChild[root];
outputFile ← Rope.Substr[outputFile, 0, Rope.Length[outputFile]-Rope.Length[".thy"]];
plotControl ← Rope.Cat[
Rope.Cat["PLOT[\"", "Jasmine Model: ", outputFile, "\", "],
Rope.Cat[":", "1ns", ", "],
Rope.Concat["-1", ", "],
Rope.Concat["6", ", "],
Rope.Cat[driveNode, ", ", lastNode]
];
plotControl ← Rope.Concat[plotControl, "];"];
TiogaFileOps.SetContents[tNode, plotControl];
Thyme Run control
tNode ← TiogaFileOps.InsertAsLastChild[root];
TiogaFileOps.SetContents[tNode, Rope.Cat["RUN[",
Rope.Cat["tMin ← ", "0ns", ", "],
Rope.Cat["tMax ← ", "100ns", "];"]
]];
}; --PrintCircuit
PrintInstanceNodes: PROC [tRoot: TNode, model: SymTab.Ref] = {
AssignNodes: PROC [mapX, mapY: NAT] RETURNS [m1, n1, m2, n2: NAT] = {
For a given X location, will see successively decreasing Y locations, before next X.
SELECT mapX FROM
> prevMapX => {
prevMapX ← mapX;
m1 ← m1Prior;
m2 ← m1Prior ← m1.SUCC;
n1 ← n2 ← n1Prior← baseMapY;
};
= prevMapX => {
IF supraBaseCount#0 THEN {
m2 ← m1 ← m1Prior;
n1 ← n1Prior;
n2 ← n1Prior ← baseMapY+supraBaseCount;
supraBaseCount ← 0;
}
ELSE {
m2 ← m1 ← m1Prior;
n1 ← n1Prior;
n2 ← n1Prior ← n1.PRED;
};
};
< prevMapX => Error["Disordered Thyme nodes"];
ENDCASE => NULL;
};
NameNode: PROC [idX, idY: NAT] RETURNS [nodeName: Rope.ROPE] = {
nodeName ← Rope.Cat["m", Convert.RopeFromInt[idX], "n", Convert.RopeFromInt[idY]];
FOR nodes: LIST OF Rope.ROPE ← nodeNames, nodes.rest UNTIL nodes=NIL DO
IF Rope.Equal[nodes.first, Rope.Cat[nodeName, nodeSeparator]] THEN RETURN;
ENDLOOP;
nodeNames ← CONS[Rope.Cat[nodeName, nodeSeparator], nodeNames];
};
NameInstance: PROC [element: Element] RETURNS [name: Rope.ROPE] = {
SELECT element FROM
contact => {
name ← Rope.Cat[name, "CON", Convert.RopeFromInt[conID]];
conID ← conID.SUCC};
wire => {
name ← Rope.Cat[name, "WIR", Convert.RopeFromInt[wireID]];
wireID ← wireID.SUCC};
transistor => {
name ← Rope.Cat[name, "XTR", Convert.RopeFromInt[xtorID]];
xtorID ← xtorID.SUCC};
ENDCASE => Error["Unknown model element"];
};
WireElement: PROC [mapX, mapY: NAT, macro: Jasmine.JasmineMacro] = {
Model: Resistor (with Stray)
m1, n1, m2, n2: NAT;
Area: Rope.ROPE ← Convert.RopeFromInt[macro.wireArea];
Perim: Rope.ROPE ← Convert.RopeFromInt[macro.wirePerimeter];
[m1, n1, m2, n2] ← AssignNodes[mapX, mapY];
subTNodeInstance ← Rope.Cat[
Rope.Cat[NameInstance[wire], ": Resistor"],
Rope.Cat["[", NameNode[m1, n1], nodeSeparator, NameNode[m2, n2], "] = "],
Rope.Cat[Convert.RopeFromReal[macro.resistance], "K", ";"]
];
-- Thyme syntax for Strays:
-- area: a; perimeter: p
-- 1st metal: M; 2nd metal: M2
-- poly: P; n diffusion: nD; p diffusion: pD
instNames ← CONS[subTNodeInstance, instNames];
subTNodeInstance ← Rope.Cat[
Rope.Cat[NameInstance[wire], ": Stray"],
Rope.Cat["[", NameNode[m1, n1], " | ",
SELECT macro.macroType FROM
m1Wire => Rope.Cat["aM←", Area, ", pM←", Perim],
m2Wire => Rope.Cat["aM2←", Area, ", pM2←", Perim],
nDifWire => Rope.Cat["anD←", Area, ", pnD←", Perim],
pDifWire => Rope.Cat["apD←", Area, ", ppD←", Perim],
polyWire => Rope.Cat["aP←", Area, ", pP←", Perim],
ENDCASE => ERROR,
"];"],
];
instNames ← CONS[subTNodeInstance, instNames];
};
ContactElement: PROC [mapX, mapY: NAT, macro: Jasmine.JasmineMacro] = {
Model: Resistive T junction
m1, n1, m2, n2: NAT;
nodeBranches: Rope.ROPENIL;
[m1, n1, m2, n2] ← AssignNodes[mapX, mapY];
SELECT macro.branch FROM
T => {
[m1, n1, m2, n2] ← AssignNodes[mapX, mapY-1];
nodeBranchesRope.Cat["[", NameNode[m1, n1], nodeSeparator, NameNode[m2, n2], "] = "];
};
leftT, rightT => {
[m1, n1, m2, n2] ← AssignNodes[mapX, mapY];
nodeBranchesRope.Cat["[", NameNode[m1, n1], nodeSeparator, NameNode[m2, n2], "] = "];
};
inverseT => {
[m1, n1, m2, n2] ← AssignNodes[mapX, mapY+1];
nodeBranchesRope.Cat["[", NameNode[m1, n1], nodeSeparator, NameNode[m2, n2], "] = "];
};
ENDCASE => {
[m1, n1, m2, n2] ← AssignNodes[mapX, mapY];
nodeBranchesRope.Cat["[", NameNode[m1, n1], nodeSeparator, NameNode[m2, n2], "] = "];
};
subTNodeInstance ← Rope.Cat[
Rope.Cat[NameInstance[contact], ": Resistor"],
nodeBranches,
Rope.Cat[Convert.RopeFromReal[macro.resistance], "K", ";"]
];
instNames ← CONS[subTNodeInstance, instNames];
};
TransistorElement: PROC [mapX, mapY: NAT, macro: Jasmine.JasmineMacro] = {
m1, n1, m2, n2: NAT;
[m1, n1, m2, n2] ← AssignNodes[mapX, mapY];
IF macro.xtorAspect=gateTied THEN { --treat as capacitor
subTNodeInstance ← Rope.Cat[
Rope.Cat[NameInstance[transistor], ": Stray"],
Rope.Cat["[", NameNode[m1, n1], " | ",
Rope.Cat["aG←", Convert.RopeFromInt[macro.xtorLength*macro.xtorWidth], ", pG←", Convert.RopeFromInt[2*macro.xtorLength+2*macro.xtorWidth], "];"]
]];
}
ELSE { --regular transistor
Model: Source attached to a node; gate to input function; drain grounded
subTNodeInstance ← Rope.Cat[
Rope.Cat[NameInstance[transistor], ": "],
SELECT macro.xtorType FROM
nE => "ETran",
pE => "CTran",
ENDCASE => ERROR,
Rope.Concat[Rope.Cat["[", Rope.Cat[driveNode, nodeSeparator, NameNode[m1, n1]], ", Gnd", " | "],
Rope.Cat["L←", Convert.RopeFromInt[macro.xtorLength], ", "]],
Rope.Cat["W←", Convert.RopeFromInt[macro.xtorWidth], ", "],
Rope.Cat["sdExtend←", Convert.RopeFromInt[macro.xtorExtn], "];"]
];
};
instNames ← CONS[subTNodeInstance, instNames];
};
PrintNodes: PROC = {
lastNode ← Rope.Substr[base: nodeNames.first, len: (Rope.Length[nodeNames.first]-Rope.Length[nodeSeparator])];
nodeNames ← Reverse[nodeNames];
FOR nodes: LIST OF Rope.ROPE ← nodeNames, nodes.rest UNTIL nodes=NIL DO
subTNodeWires ← Rope.Cat[subTNodeWires, nodes.first];
ENDLOOP;
subTNodeWires← Rope.Substr[base: subTNodeWires, len: (Rope.Length[subTNodeWires]-Rope.Length[nodeSeparator])];
subTNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[subTNode, Rope.Cat[subTNodeWires, ": Node;"]];
};
PrintInstances: PROC = {
instNames ← Reverse[instNames];
FOR instances: LIST OF Rope.ROPE ← instNames, instances.rest UNTIL instances=NIL DO
subTNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[subTNode, instances.first];
ENDLOOP;
};
subTNodeInstance, subTNodeWires: Rope.ROPE;
nodeNames, instNames: LIST OF Rope.ROPENIL;
nodeSeparator: Rope.ROPE ← ", ";
tNode, subTNode: TNode;
nodeID: NAT ← 0;
conID, wireID, xtorID: NAT ← 1;
macroCount, supraBaseCount: NAT ← 0;
thereIs, baseSet: BOOLFALSE;
previewedY: BOOLFALSE;
prevMapX: NAT ← 0;
baseMapY: NAT ← 0;
m1Prior: NAT ← 1;
n1Prior: NAT ← 1;
val: REF ANY;
nodeNames ← CONS[Rope.Concat[driveNode, ", "], nodeNames];
tNode ← TiogaFileOps.InsertAsLastChild[tRoot];
FOR indices: LIST OF Jasmine.MacroLocation ← Jasmine.locations, indices.rest UNTIL indices=NIL DO
previewedY ← FALSE;
supraBaseCount ← 0;
[thereIs, val] ← SymTab.Fetch[model, Jasmine.MapConvert[indices.first]];
IF thereIs THEN {
macro: Jasmine.JasmineMacro ← NARROW[val];
x: INT ← indices.first.mapX;
y: INT ← indices.first.mapY;
IF NOT baseSet THEN {
baseMapY ← n1Prior ← y;
baseSet ← TRUE;
};
IF (y > baseMapY) AND NOT previewedY THEN {
Handles the case where the first Y element is above the baseline.
Counts how many elements are above the baseline before dispatching so that Thyme node names remain consistent.
supraBaseCount ← supraBaseCount.SUCC;
FOR k: INT IN [Jasmine.md.mapYMin..y] DO
location: Jasmine.MacroLocation ← NEW[Jasmine.MacroLocationRec ← [x, k]];
IF k=baseMapY THEN {previewedY ← TRUE; EXIT};
[thereIs, val] ← SymTab.Fetch[model, Jasmine.MapConvert[location]];
IF thereIs THEN supraBaseCount ← supraBaseCount.SUCC;
ENDLOOP;
};
SELECT macro.macroType FROM
m1Wire, m2Wire, nDifWire, pDifWire, polyWire => WireElement[x, y, macro];
nDifCont, pDifCont, polyCont, Via => ContactElement[x, y, macro];
nTran, nTranL, pTran, pTranL => TransistorElement[x, y, macro];
ENDCASE => NULL;
macroCount ← macroCount.SUCC;
};
ENDLOOP;
PrintNodes[];
PrintInstances[];
subTNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[subTNode, Rope.Cat["driver: BusDriver[", driveNode, ", Vdd, ", "m1n1", "];"]
];
subTNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[subTNode, Rope.Cat["driveSignal: Pulse[", driveNode, " | amplitude𡤅V, offset𡤀, period𡤅ns, width𡤅ns, tRise𡤂ns, tFall𡤂ns, tDelay𡤀", "];"]
];
subTNode ← TiogaFileOps.InsertAsLastChild[tNode];
TiogaFileOps.SetContents[subTNode, "};\n"];
}; --PrintInstanceNodes
ShowThyme: PUBLIC PROC [workingDir, thyFile: Rope.ROPE] = {
thyHandle: spGlobals.Handle ← spGlobals.MakeThymeViewers[workingDir];
ViewerTools.SetContents[thyHandle.input, thyFile];
spMain.NormalRun[thyHandle];
};
Reverse: PROC [ropes: LIST OF Rope.ROPE] RETURNS [revRopes: LIST OF Rope.ROPENIL] = {
WHILE ropes#NIL DO revRopes ← CONS [ropes.first, revRopes]; ropes ← ropes.rest ENDLOOP;
};
END...of JasmineThymeImpl