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]; 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] = { 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] = { 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] = { m1, n1, m2, n2: NAT; nodeBranches: Rope.ROPE _ NIL; [m1, n1, m2, n2] _ AssignNodes[mapX, mapY]; SELECT macro.branch FROM T => { [m1, n1, m2, n2] _ AssignNodes[mapX, mapY-1]; nodeBranches _ Rope.Cat["[", NameNode[m1, n1], nodeSeparator, NameNode[m2, n2], "] = "]; }; leftT, rightT => { [m1, n1, m2, n2] _ AssignNodes[mapX, mapY]; nodeBranches _ Rope.Cat["[", NameNode[m1, n1], nodeSeparator, NameNode[m2, n2], "] = "]; }; inverseT => { [m1, n1, m2, n2] _ AssignNodes[mapX, mapY+1]; nodeBranches _ Rope.Cat["[", NameNode[m1, n1], nodeSeparator, NameNode[m2, n2], "] = "]; }; ENDCASE => { [m1, n1, m2, n2] _ AssignNodes[mapX, mapY]; nodeBranches _ Rope.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 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.ROPE _ NIL; nodeSeparator: Rope.ROPE _ ", "; tNode, subTNode: TNode; nodeID: NAT _ 0; conID, wireID, xtorID: NAT _ 1; macroCount, supraBaseCount: NAT _ 0; thereIs, baseSet: BOOL _ FALSE; previewedY: BOOL _ FALSE; 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 { 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_5V, offset_0, period_5ns, width_5ns, tRise_2ns, tFall_2ns, tDelay_0", "];"] ]; 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.ROPE _ NIL] = { WHILE ropes#NIL DO revRopes _ CONS [ropes.first, revRopes]; ropes _ ropes.rest ENDLOOP; }; END...of JasmineThymeImpl fJasmineThymeImpl.mesa Copyright c 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 Thyme Run control For a given X location, will see successively decreasing Y locations, before next X. Model: Resistor (with Stray) Model: Resistive T junction Model: Source attached to a node; gate to input function; drain grounded 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. Κ ˜™Icodešœ Οmœ1™K˜Kš   œžœžœžœžœ˜EšœT™Tšžœžœ˜šœ˜Kšœ˜Kšœ˜Kšœžœ˜Kšœ˜Kšœ˜—šœ˜šžœžœ˜Kšœ˜Kšœ ˜ Kšœ'˜'Kšœ˜K˜—šžœ˜Kšœ˜Kšœ ˜ Kšœžœ˜K˜—K˜—Kšœ/˜/—Kšžœžœ˜K˜—K˜š Πbnœžœ žœžœžœ˜@KšœR˜Rš žœžœžœžœžœžœž˜GKšžœ<žœžœ˜JKšžœ˜ —Kšœ žœ/˜?Kšœ˜—K˜š  œžœžœ žœ˜Cšžœ ž˜šœ ˜ Kšœ:˜:Kšœžœ˜—šœ ˜ Kšœ;˜;Kšœžœ˜—šœ˜Kšœ;˜;Kšœžœ˜—Kšžœ#˜*—K˜—K˜š  œžœžœ"˜DKšœ™Kšœžœ˜Kšœ žœ'˜6Kšœ žœ,˜