<> <> <> <> <> DIRECTORY CD USING [ObPtr, ApplicationPtr, ApplicationList, lambda], CDDirectory USING [Name], CDObjectProcs USING [FetchFurther], CDProperties USING [GetPropFromObject, GetPropFromApplication], CDIO USING [GetWorkingDirectory], TerminalIO USING [WriteRope], Atom USING [PropList, PutPropOnList, GetPropFromList, RemPropFromList], RefTab USING [Ref, Pairs, EachPairAction], SymTab USING [Ref, Create, Store, Fetch], Rope USING [ROPE, Cat, Length, Fetch, Find, Replace], Ascii USING [Letter, Digit], IO USING [STREAM, atom, card, char, int, Put, PutF, PutR, PutRope, rope, RopeFromROS, ROS, time, Close], Convert USING [RopeFromInt, RopeFromRope], FS USING [StreamOpen, Error, ExpandName], TiogaOps USING [PutProp], TiogaFileOps USING [Ref, CreateRoot, InsertNode, InsertAsLastChild, SetContents, AddLooks, SetFormat, SetStyle, Store], UserCredentials USING [Get], PupDefs USING [GetMyName], SpinifexAtoms USING [ spinifex, SignalName, InstanceName, thymePrint, rosePrint], SpinifexCircuit USING [ LogicalCell, Circuit, CircuitNode, AreaPerimRec, NodeLinkage, MergeRec, MergeRecList, TechHandle, FindRootNode, SignalName], SpinifexOutput ; SpinifexOutputImpl: CEDAR PROGRAM IMPORTS CDDirectory, CDObjectProcs, CDProperties, CDIO, TerminalIO, Atom, RefTab, SymTab, Rope, Ascii, IO, Convert, FS, TiogaOps, TiogaFileOps, UserCredentials, PupDefs, SpinifexAtoms, SpinifexCircuit EXPORTS SpinifexOutput ~ BEGIN <<-- TYPES from SpinifexCircuit.>> Circuit: TYPE ~ SpinifexCircuit.Circuit; CircuitNode: TYPE ~ SpinifexCircuit.CircuitNode; AreaPerimRec: TYPE ~ SpinifexCircuit.AreaPerimRec; NodeLinkage: TYPE ~ SpinifexCircuit.NodeLinkage; MergeRec: TYPE ~ SpinifexCircuit.MergeRec; TechHandle: TYPE ~ SpinifexCircuit.TechHandle; MergeRecList: TYPE ~ SpinifexCircuit.MergeRecList; SignalName: TYPE ~ SpinifexCircuit.SignalName; LogicalCell: TYPE ~ SpinifexCircuit.LogicalCell; <<-- Implementation.>> isPort: ATOM ~ $SpinifexIsPort; carryThroughNodes: ATOM ~ $SpinifexThroughNodes; nodeName: ATOM ~ $SpinifexNodeName; <<-- All we are really interested in is .first in the following MergeRecList-s but these cannot be broken up so we just point to LIST.>> CarryThrough: TYPE ~ RECORD [numCT: CARDINAL, key: REF CircuitNode, merge: MergeRecList, chainTail: LIST OF CD.ApplicationPtr]; AddPorts: PROCEDURE [cellList: LIST OF REF LogicalCell, globalNames: SymTab.Ref] ~ { <<-- Process Circuits top down. Node is a port iff it appears in some merge directory.>> TagSubcircuitNode: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN] -- ~ { portNode: REF CircuitNode ~ NARROW[key]; merges: MergeRecList ~ NARROW[val]; portNode.properties _ portNode.properties.PutPropOnList[prop~ isPort, val~ isPort]; FOR ml: MergeRecList _ merges, ml.rest WHILE ml # NIL DO <<-- Skip the first Application (Guaranteed to be at least one).>> FOR applChain: LIST OF CD.ApplicationPtr _ ml.first.applChain.rest, applChain.rest WHILE applChain # NIL DO intermediateCircuit: REF Circuit ~ NARROW[ CDProperties.GetPropFromObject[ from~applChain.first.ob, prop~SpinifexAtoms.spinifex]]; <<-- An interface carry through node is required in intermediateCircuit.>> throughNodes: LIST OF CarryThrough ~ NARROW[ intermediateCircuit.properties.GetPropFromList[ carryThroughNodes] ]; <<-- Hmm, is ml already on throughNodes list? We'd better check.>> foundIt: BOOLEAN _ FALSE; lag: LIST OF CarryThrough _ NIL; FOR existingTNs: LIST OF CarryThrough _ throughNodes, existingTNs.rest WHILE existingTNs # NIL AND ~foundIt DO IF portNode = existingTNs.first.key THEN { thisAppl: LIST OF CD.ApplicationPtr _ ml.first.applChain; FOR existingAppl: LIST OF CD.ApplicationPtr _ existingTNs.first.merge.first.applChain, existingAppl.rest UNTIL thisAppl.first = applChain.first DO IF existingAppl = NIL OR thisAppl.first # existingAppl.first THEN EXIT; thisAppl _ thisAppl.rest; REPEAT FINISHED => foundIt _ TRUE ENDLOOP }; lag _ existingTNs; ENDLOOP; IF ~foundIt THEN { IF lag # NIL THEN { IF lag.rest # NIL THEN ERROR; lag.rest _ LIST[ CarryThrough[ 0, portNode, ml, applChain]]; } ELSE { IF throughNodes # NIL THEN ERROR; intermediateCircuit.properties _ intermediateCircuit.properties.PutPropOnList[ carryThroughNodes, NARROW[ LIST[ CarryThrough[ 1, portNode, ml, applChain]], LIST OF CarryThrough -- Note: this NARROW is necessary because the LIST constructor is not defined for general lists, see CLRM for details. (Mark Shand for Cedar 5.2 July 13, 1984) --] ]; } } ENDLOOP; ENDLOOP; quit _ FALSE }; circuit: REF Circuit ~ NARROW[ CDProperties.GetPropFromObject[ from~cellList.first.cellObj, prop~SpinifexAtoms.spinifex]]; IF cellList.rest # NIL THEN AddPorts[cellList.rest, globalNames]; IF circuit.mergeDirectory # NIL THEN [] _ circuit.mergeDirectory.Pairs[ action~ TagSubcircuitNode]; FOR nl: LIST OF REF CircuitNode _ circuit.nodes, nl.rest WHILE nl # NIL DO signalName: REF SignalName ~ NARROW[nl.first.properties.GetPropFromList[ SpinifexAtoms.SignalName]]; IF signalName # NIL THEN { NULL; } ENDLOOP; }; ClearPorts: PROCEDURE [cellList: LIST OF REF LogicalCell] ~ { <<-- Clear existing ports from cells>> FOR cl: LIST OF REF LogicalCell _ cellList, cl.rest WHILE cl # NIL DO circuit: REF Circuit ~ NARROW[ CDProperties.GetPropFromObject[ from~cl.first.cellObj, prop~SpinifexAtoms.spinifex]]; circuit.properties _ circuit.properties.RemPropFromList[ carryThroughNodes]; FOR nl: LIST OF REF CircuitNode _ circuit.nodes, nl.rest WHILE nl # NIL DO node: REF CircuitNode ~ nl.first; node.properties _ node.properties.RemPropFromList[isPort]; node.properties _ node.properties.RemPropFromList[nodeName] ENDLOOP; ENDLOOP; }; PrintCircuit: PUBLIC PROCEDURE [cellList: LIST OF REF LogicalCell, formatKey: REF ANY] ~ { HierarchyRoot: PROCEDURE [cellList: LIST OF REF LogicalCell] RETURNS [CD.ObPtr] ~ INLINE { FOR cl: LIST OF REF LogicalCell _ cellList, cl.rest WHILE cl # NIL DO IF cl.rest = NIL THEN RETURN[cl.first.cellObj]; ENDLOOP; ERROR }; ReadGlobalSignals: PROCEDURE [glob: SymTab.Ref] ~ { <<-- SymTab keyed by signal names, value is use count.>> <> <<[] _ glob.Store[ "Gnd", $GlobalSignal];>> < IF error.group = user THEN { GOTO NoFile } ];>> <> <> <> <> <<[tok, id] _ globFile.GetCedarTokenRope[ ! IO.Error => EXIT; IO.EndOfStream => EXIT];>> <> <<[] _ glob.Store[ id, $GlobalSignal];>> <> < NULL;>> }; globals: SymTab.Ref; desWDir: Rope.ROPE ~ CDIO.GetWorkingDirectory[cellList.first.design]; globals _ SymTab.Create[mod~553, case~ TRUE]; FOR cl: LIST OF REF LogicalCell _ cellList, cl.rest WHILE cl # NIL DO IF ~globals.Store[CDDirectory.Name[cl.first.cellObj], $CellName] THEN NULL; <<-- Should be ERROR Duplicate name.>> ENDLOOP; ReadGlobalSignals[globals]; AddPorts[cellList, globals]; SELECT formatKey FROM <> SpinifexAtoms.thymePrint => { thymeFileName: Rope.ROPE ~ FS.ExpandName[ CDDirectory.Name[HierarchyRoot[cellList]].Cat[".thy"], desWDir].fullFName; thymeFile: TiogaFileOps.Ref ~ TiogaFileOps.CreateRoot[]; defnTextNode: TiogaFileOps.Ref; TerminalIO.WriteRope[ IO.PutR[ IO.rope["Commencing output of thyme file to \""], IO.rope[thymeFileName], IO.rope["\""]] ]; thymeFile.SetStyle["Cedar"]; defnTextNode _ thymeFile.InsertAsLastChild[]; defnTextNode.SetContents[ IO.PutR[ IO.rope[thymeFileName], IO.rope[", Written by Spinifex, "], IO.time[]] ]; <<-- Following LOOPHOLE caused by `opaque type' compiler problems.>> TRUSTED { TiogaOps.PutProp[LOOPHOLE[defnTextNode], $Comment, NEW[BOOLEAN _ TRUE]] }; FOR cl: LIST OF REF LogicalCell _ cellList, cl.rest WHILE cl # NIL DO defnTextNode _ thymeFile.InsertAsLastChild[ defnTextNode]; defnTextNode.SetFormat[ "unit"]; PrintSubcircuit[thymeFile, defnTextNode, cl.first.cellObj, globals, formatKey]; ENDLOOP; thymeFile.Store[ thymeFileName ! FS.Error => { IF error.group = user THEN { IF error.code = $illegalName THEN { thymeFile.Store[ "///temp/ThymeOut.thy" ]; TerminalIO.WriteRope[ Rope.Cat[ "\n\t", error.explanation, "\n\tExtracted output will appear in \"///temp/ThymeOut.thy\""]]; CONTINUE } ELSE { TerminalIO.WriteRope[error.explanation]; GOTO IOProblems } }; } ]; TerminalIO.WriteRope[ "  done.\n"]; EXITS IOProblems => TerminalIO.WriteRope[ "  failed.\n"]; }; <> SpinifexAtoms.rosePrint => { GenKey: INT _ 0; rootName: Rope.ROPE _ CDDirectory.Name[HierarchyRoot[cellList]]; fullRootName: Rope.ROPE; DFfile: IO.STREAM; { ENABLE FS.Error => IF error.group = user THEN { IF error.code = $illegalName THEN { rootName _ "ExtractedRoseOut"; fullRootName _ FS.ExpandName[rootName, desWDir].fullFName; DFfile _ FS.StreamOpen[fullRootName.Cat[".df"], $create]; TerminalIO.WriteRope[ Rope.Cat[ "\n\t", error.explanation, "\n\tExtracted output will appear in \"", fullRootName, ".df\""]]; GOTO AbleToOutput } ELSE { TerminalIO.WriteRope[error.explanation]; GOTO IOProblems } }; <> fullRootName _ FS.ExpandName[rootName, desWDir].fullFName; DFfile _ FS.StreamOpen[fullRootName.Cat[".df"], $create]; EXITS AbleToOutput => NULL }; TerminalIO.WriteRope[ IO.PutR[ IO.rope["Commencing output rosemary file to \""], IO.rope[fullRootName], IO.rope[".df\""]] ]; DFfile.PutF["-- %g.df written by Spinifex rosemary structure capturer, %g\n\n\n", IO.rope[rootName], IO.time[]]; DFfile.PutF["Directory %g\n\t%g.df\n", IO.rope[desWDir], IO.rope[rootName]]; FOR cl: LIST OF REF LogicalCell _ cellList, cl.rest WHILE cl # NIL DO cellFileName: Rope.ROPE _ CDDirectory.Name[cl.first.cellObj]; cellFile: TiogaFileOps.Ref ~ TiogaFileOps.CreateRoot[]; firstNode: TiogaFileOps.Ref ~ cellFile.InsertAsLastChild[]; cellFile.SetStyle["Cedar"]; firstNode.SetFormat[ "unit"]; PrintSubcircuit[cellFile, firstNode, cl.first.cellObj, globals, formatKey]; { ENABLE FS.Error => IF error.group = user THEN { IF error.code = $illegalName THEN { cellFileName _ rootName.Cat["-", Convert.RopeFromInt[GenKey]]; GenKey _ GenKey.SUCC; cellFile.Store[ FS.ExpandName[cellFileName.Cat[".sch"], desWDir].fullFName]; CONTINUE } ELSE { TerminalIO.WriteRope[error.explanation]; GOTO IOProblems } }; fName: Rope.ROPE ~ FS.ExpandName[cellFileName.Cat[".sch"], desWDir].fullFName; cellFile.Store[ fName] }; DFfile.PutF["-- \"%g\"\n %g.sch\n", IO.rope[CDDirectory.Name[cl.first.cellObj]], IO.rope[cellFileName]]; ENDLOOP; DFfile.Close[]; TerminalIO.WriteRope[ "  done.\n"]; EXITS IOProblems => TerminalIO.WriteRope[ "  failed.\n"]; }; ENDCASE => { TerminalIO.WriteRope[ "Warning: Unknown output format, no file written.\n"]; }; ClearPorts[cellList]; }; PrintSubcircuit: PROCEDURE [root, circuitDefn: TiogaFileOps.Ref, cellObj: CD.ObPtr, GlobalNames: SymTab.Ref, formatKey: REF ANY] ~ { <> PrintStrayProc: TYPE ~ PROCEDURE [ Stream: IO.STREAM, node: REF CircuitNode, specialName: Rope.ROPE _ NIL]; PrintRoseStray: PrintStrayProc ~ { NULL }; PrintThymeStray: PrintStrayProc ~ { startedAPList: BOOLEAN _ FALSE; FOR apList: LIST OF AreaPerimRec _ node.dim, apList.rest WHILE apList # NIL DO r: Rope.ROPE ~ tech.spinifexLayerNames[ apList.first.layer].thymeName; IF r = NIL THEN LOOP; IF ~startedAPList THEN { Stream.Put[ IO.rope[" ?: Stray["]]; IF specialName # NIL THEN Stream.Put[ IO.rope[specialName]] ELSE PrintNode[Stream, node]; Stream.Put[IO.rope["|"]] } ELSE Stream.Put[ IO.char[ ',]]; Stream.PutF[ " a%g_%g, p%g_%g", IO.rope[r], IO.int[apList.first.area/(CD.lambda*CD.lambda)], IO.rope[r], IO.int[apList.first.perim/CD.lambda]]; startedAPList _ TRUE ENDLOOP; IF startedAPList THEN Stream.PutRope["];"]; }; QuoteProc: TYPE ~ PROCEDURE [name: Rope.ROPE] RETURNS [Rope.ROPE]; QuoteRose: QuoteProc ~ { RETURN [Convert.RopeFromRope[name]] }; QuoteThyme: QuoteProc ~ { l: INT ~ name.Length[]; IF l = 0 THEN RETURN ["$$"]; FOR i: INT IN [0..l) DO c: CHAR ~ name.Fetch[i]; IF ~Ascii.Letter[c] AND ~Ascii.Digit[c] THEN EXIT; REPEAT FINISHED => RETURN [name] ENDLOOP; { <> constructedName: Rope.ROPE _ Rope.Cat["$", name]; dollarPosnSUCC: INT _ 1; WHILE (dollarPosnSUCC _ constructedName.Find["$", dollarPosnSUCC]) # -1 DO constructedName _ constructedName.Replace[dollarPosnSUCC, 1, "$$"]; dollarPosnSUCC _ dollarPosnSUCC + 2 -- Jump over inserted $$ ENDLOOP; RETURN [constructedName.Cat["$"]] } }; <> PrintRoseNode: SpinifexOutput.NodePrintProc -- [ stream: IO.STREAM, node: REF CircuitNode] -- ~ { printName: REF ANY ~ node.properties.GetPropFromList[nodeName]; IF printName = NIL THEN ERROR; WITH printName SELECT FROM local: REF Local => stream.PutF[ Quote[Rope.Cat[ localBase, Convert.RopeFromInt[local.numL]]] ]; port: REF Port => stream.PutF[ Quote[Rope.Cat[ portBase, Convert.RopeFromInt[port.numP]]] ]; named: REF Named => stream.Put[ IO.rope[Quote[named.name]]]; ENDCASE => ERROR; }; PrintThymeNode: SpinifexOutput.NodePrintProc -- [ stream: IO.STREAM, node: REF CircuitNode] -- ~ { printName: REF ANY ~ node.properties.GetPropFromList[nodeName]; IF printName = NIL THEN ERROR; WITH printName SELECT FROM local: REF Local => stream.Put[ IO.rope[ localBase], IO.card[local.numL]]; port: REF Port => stream.Put[ IO.rope[ portBase], IO.card[port.numP]]; named: REF Named => stream.Put[ IO.rope[Quote[named.name]]]; ENDCASE => ERROR; }; QNodeName: PROCEDURE [node: REF CircuitNode] RETURNS [name: Rope.ROPE] ~ { <> quotedName: IO.STREAM ~ IO.ROS[]; PrintNode[ quotedName, node]; name _ quotedName.RopeFromROS[] }; PortHead: TiogaFileOps.Ref; PrintHeadProc: TYPE ~ PROCEDURE [ name: Rope.ROPE]; PrintRoseHead: PrintHeadProc ~ { output.PutF[ "-- %g", IO.rope[ name]]; circuitDefn.SetContents[ output.RopeFromROS[]]; <<-- Following LOOPHOLE caused by `opaque type' compiler problems.>> TRUSTED { TiogaOps.PutProp[LOOPHOLE[circuitDefn], $Comment, NEW[BOOLEAN _ TRUE]] }; output _ output.ROS[]; output.PutF[ "(CreatingUser \"%g\")", IO.rope[UserCredentials.Get[].name]]; AppendTiogaNode[output]; output _ output.ROS[]; output.PutF[ "(CreationTime \"%g\")", IO.time[]]; AppendTiogaNode[output]; output _ output.ROS[]; output.PutF[ "(CreationSite \"%g\")", IO.rope[PupDefs.GetMyName[]]]; AppendTiogaNode[output]; output _ output.ROS[]; output.PutRope[ "(DerivingProgram \"Spinifex\" \"TrashForNow\")"]; AppendTiogaNode[output]; output _ output.ROS[]; output.PutF[ "(CellTypeName %g)", IO.rope[name]]; AppendTiogaNode[output]; output _ output.ROS[]; output.Put[IO.rope[ "(Ports"]]; AppendTiogaNode[output]; <> PortHead _ currLine; lastNodeNode _ currLine; output _ output.ROS[] }; PrintThymeHead: PrintHeadProc ~ { output.Put[ IO.rope[ name], IO.rope[ ": circuit["]]; }; PrintFormalProc: TYPE ~ PROCEDURE [ qName: Rope.ROPE, portNum: CARDINAL, node: REF CircuitNode _ NIL]; PrintRoseFormal: PrintFormalProc ~ { portDef: TiogaFileOps.Ref ~ PortHead.InsertAsLastChild[]; <> output.PutF[ "(%g)", IO.rope[qName] ]; portDef.SetContents[output.RopeFromROS[]]; portDef.SetFormat[ "code"]; output _ output.ROS[]; output.PutF[ "(N %g", IO.rope[qName]]; IF node # NIL THEN { WITH node.properties.GetPropFromList[ nodeName] SELECT FROM nameRec: REF Named => { output.PutRope[" (G D)"]; IF nameRec.aliases # NIL THEN PrintNodeAlias[node, nameRec.aliases] }; ENDCASE => output.PutRope[" (G P)"]; }; output.PutRope[")"]; AppendTiogaNode[output]; output _ output.ROS[]; <> output.PutF[ "(PN %g %g)", IO.rope[qName], IO.rope[qName]]; AppendTiogaNode[output]; output _ output.ROS[] }; PrintThymeFormal: PrintFormalProc ~ { output.Put[ IO.rope[IF portNum = CountBase THEN " " ELSE ", "], IO.rope[qName] ] }; PrintStartBodyProc: TYPE ~ PROCEDURE [ cellName: Rope.ROPE]; PrintRoseStartBody: PrintStartBodyProc ~ { portClose: TiogaFileOps.Ref ~ PortHead.InsertAsLastChild[]; privateStart: TiogaFileOps.Ref ~ PortHead.InsertNode[]; portClose.SetContents[")"]; portClose.SetFormat[ "code"]; privateStart.SetContents["(PrivateFollows)"]; portClose.SetFormat[ "code"]; }; PrintThymeStartBody: PrintStartBodyProc ~ { output.Put[ IO.rope["] = {"]]; circuitDefn.SetContents[ output.RopeFromROS[]]; circuitDefn.AddLooks[0, cellName.Length[], 'b, root]; output _ output.ROS[] }; PrintLocalNodeProc: TYPE ~ PROCEDURE [ node: REF CircuitNode]; PrintRoseLocalNode: PrintLocalNodeProc ~ { <> output.PutRope["(N "]; PrintNode[ output, node]; WITH node.properties.GetPropFromList[ nodeName] SELECT FROM nameRec: REF Named => { output.PutRope[" (G D)"]; IF nameRec.aliases # NIL THEN PrintNodeAlias[node, nameRec.aliases] }; ENDCASE => output.PutRope[" (G P)"]; output.PutRope[")"]; AppendTiogaNode[output]; output _ output.ROS[]; lastNodeNode _ currLine; }; PrintThymeLocalNode: PrintLocalNodeProc ~ { WITH node.properties.GetPropFromList[ nodeName] SELECT FROM nameRec: REF Named => IF nameRec.aliases # NIL THEN PrintNodeAlias[node, nameRec.aliases]; ENDCASE; PrintNode[ output, node]; output.Put[ IO.rope[ ": node;"]]; PrintStray[ output, node]; AppendTiogaNode[output]; output _ output.ROS[]; }; PrintNodeAliasProc: TYPE ~ PROCEDURE [ node: REF CircuitNode, aliases: LIST OF Rope.ROPE]; PrintRoseNodeAlias: PrintNodeAliasProc ~ { output.Put[ IO.rope[ " (A "]]; PrintNode[ output, node]; FOR al: LIST OF Rope.ROPE _ aliases, al.rest WHILE al # NIL DO r: Rope.ROPE _ al.first; output.Put[ IO.rope[ " "], IO.rope[ Quote[r]] ]; ENDLOOP; output.Put[ IO.rope[ ")"]]; }; PrintThymeNodeAlias: PrintNodeAliasProc ~ { IF node.properties.GetPropFromList[ isPort] = isPort THEN RETURN; output.Put[ IO.rope[ "-- ALIAS[ "]]; PrintNode[ output, node]; FOR al: LIST OF Rope.ROPE _ aliases, al.rest WHILE al # NIL DO output.Put[ IO.rope[ ", "], IO.rope[ Quote[al.first]] ]; ENDLOOP; output.Put[ IO.rope[ "] --"]]; AppendTiogaNode[output]; <<-- Following LOOPHOLE caused by `opaque type' compiler problems.>> TRUSTED { TiogaOps.PutProp[LOOPHOLE[currLine], $Comment, NEW[BOOLEAN _ TRUE]] }; output _ output.ROS[] }; PrintInstanceHeadProc: TYPE ~ PROCEDURE [ qInstName, defName: Rope.ROPE]; PrintRoseInstanceHead: PrintInstanceHeadProc ~ { output.PutF[ "(CI %g %g (CIC", IO.rope[qInstName], IO.rope[Quote[defName]] ]; }; PrintThymeInstanceHead: PrintInstanceHeadProc ~ { output.PutF[ "%g: %g[", IO.rope[qInstName], IO.rope[Quote[defName]]]; }; PrintActualProc: TYPE ~ PROCEDURE [ qActualNode, qFormalPort: Rope.ROPE, actualNum: CARDINAL]; PrintRoseActual: PrintActualProc ~ { output.PutF[ " (%g %g)", IO.rope[qFormalPort], IO.rope[qActualNode] ] }; PrintThymeActual: PrintActualProc ~ { IF actualNum # CountBase THEN output.PutRope[ ", "]; output.PutRope[ qActualNode]; }; PrintInventedProc: TYPE ~ PROCEDURE [node: REF CircuitNode] RETURNS [Rope.ROPE]; lastNodeNode: TiogaFileOps.Ref; -- Set in PrintRoseHead & PrintRoseLocalNode PrintRoseInvented: PrintInventedProc ~ { tnName: Rope.ROPE; nodeStopperDecls: IO.STREAM _ IO.ROS[]; [tnName, nodeStoppers] _ FindUnique[stopperBase, nodeStoppers]; tnName _ Quote[tnName]; nodeStopperDecls.Put[ IO.rope["(N "], IO.rope[tnName], IO.rope[")"]]; PrintStray[ nodeStopperDecls, node, tnName]; lastNodeNode _ lastNodeNode.InsertNode[]; lastNodeNode.SetContents[nodeStopperDecls.RopeFromROS[]]; lastNodeNode.SetFormat[ "code"]; RETURN [tnName] }; PrintThymeInvented: PrintInventedProc ~ { <<-- Declare `Node Stoppers' for nodes which are not part of current cell's circuit, but nevertheless appear on a subcircuit's parameter list due to mergings which occur in other applications of the subcircuit.>> tnName: Rope.ROPE; nodeStopperDecls: IO.STREAM _ IO.ROS[]; [tnName, nodeStoppers] _ FindUnique[stopperBase, nodeStoppers]; tnName _ Quote[tnName]; nodeStopperDecls.Put[ IO.rope[tnName], IO.rope[": node;"]]; PrintStray[ nodeStopperDecls, node, tnName]; AppendTiogaNode[nodeStopperDecls]; nodeStoppers _ nodeStoppers.SUCC; RETURN [tnName] }; PrintInstanceEndProc: TYPE ~ PROCEDURE []; PrintRoseInstanceEnd: PrintInstanceEndProc ~ { output.PutRope[ "))"]; AppendTiogaNode[output]; output _ output.ROS[] }; PrintThymeInstanceEnd: PrintInstanceEndProc ~ { output.PutRope[ "];"]; AppendTiogaNode[output]; output _ output.ROS[] }; PrintBodyEndProc: TYPE ~ PROCEDURE []; PrintRoseBodyEnd: PrintBodyEndProc ~ { }; PrintThymeBodyEnd: PrintBodyEndProc ~ { output.PutRope[ "};"]; AppendTiogaNode[output]; output _ output.ROS[] }; AppendTiogaNode: PROCEDURE [Stream: IO.STREAM] ~ { currLine _ circuitDefn.InsertAsLastChild[currLine]; currLine.SetContents[Stream.RopeFromROS[]]; currLine.SetFormat[ "code"] }; Symbols: SymTab.Ref; UsedSymbol: PROCEDURE [r: Rope.ROPE] RETURNS [BOOLEAN] ~ { RETURN [GlobalNames.Fetch[r].found OR Symbols.Fetch[r].found] }; FindUnique: PROCEDURE [ base: Rope.ROPE, start: INTEGER, val: REF ANY _ NIL] RETURNS [rope: Rope.ROPE, count: INTEGER] ~ { <<-- Finds first string of form base-int where int>=start where base-int is not in Symbols. Enters the found string in Symbols.>> count _ start; DO rope _ base.Cat[Convert.RopeFromInt[count]]; IF ~UsedSymbol[rope] THEN { [] _ Symbols.Store[rope, val]; RETURN }; count _ count.SUCC; ENDLOOP; }; InstanceName: PROCEDURE [appl: CD.ApplicationPtr, nonameBase: Rope.ROPE, nonameCount: CARDINAL] RETURNS [qInstName: Rope.ROPE, newCount: CARDINAL] ~ { WITH CDProperties.GetPropFromApplication[ appl, SpinifexAtoms.InstanceName] SELECT FROM r: Rope.ROPE => { newCount _ nonameCount; -- Irrelevant in this case, so return old value. IF ~UsedSymbol[r] THEN { [] _ Symbols.Store[r, NIL]; qInstName _ r } ELSE qInstName _ FindUnique[r.Cat[CountSep], CountBase].rope }; ENDCASE => [qInstName, newCount] _ FindUnique[nonameBase, nonameCount]; qInstName _ Quote[qInstName] }; <<-- Output format customization>> PrintStray: PrintStrayProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeStray, SpinifexAtoms.rosePrint => PrintRoseStray, ENDCASE => ERROR; Quote: QuoteProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => QuoteThyme, SpinifexAtoms.rosePrint => QuoteRose, ENDCASE => ERROR; PrintNode: SpinifexOutput.NodePrintProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeNode, SpinifexAtoms.rosePrint => PrintRoseNode, ENDCASE => ERROR; PrintHead: PrintHeadProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeHead, SpinifexAtoms.rosePrint => PrintRoseHead, ENDCASE => ERROR; PrintFormal: PrintFormalProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeFormal, SpinifexAtoms.rosePrint => PrintRoseFormal, ENDCASE => ERROR; PrintStartBody: PrintStartBodyProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeStartBody, SpinifexAtoms.rosePrint => PrintRoseStartBody, ENDCASE => ERROR; PrintLocalNode: PrintLocalNodeProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeLocalNode, SpinifexAtoms.rosePrint => PrintRoseLocalNode, ENDCASE => ERROR; PrintNodeAlias: PrintNodeAliasProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeNodeAlias, SpinifexAtoms.rosePrint => PrintRoseNodeAlias, ENDCASE => ERROR; PrintInstanceHead: PrintInstanceHeadProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeInstanceHead, SpinifexAtoms.rosePrint => PrintRoseInstanceHead, ENDCASE => ERROR; PrintActual: PrintActualProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeActual, SpinifexAtoms.rosePrint => PrintRoseActual, ENDCASE => ERROR; PrintInvented: PrintInventedProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeInvented, SpinifexAtoms.rosePrint => PrintRoseInvented, ENDCASE => ERROR; PrintInstanceEnd: PrintInstanceEndProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeInstanceEnd, SpinifexAtoms.rosePrint => PrintRoseInstanceEnd, ENDCASE => ERROR; PrintBodyEnd: PrintBodyEndProc ~ SELECT formatKey FROM SpinifexAtoms.thymePrint => PrintThymeBodyEnd, SpinifexAtoms.rosePrint => PrintRoseBodyEnd, ENDCASE => ERROR; ignoreChildNames: BOOLEAN ~ formatKey = SpinifexAtoms.rosePrint; Local: TYPE ~ RECORD [numL: CARDINAL]; Port: TYPE ~ RECORD [numP: CARDINAL]; Named: TYPE ~ RECORD [name: Rope.ROPE, aliases: LIST OF Rope.ROPE _ NIL]; circuit: REF Circuit ~ NARROW[ CDProperties.GetPropFromObject[ from~cellObj, prop~SpinifexAtoms.spinifex]]; tech: REF TechHandle ~ circuit.technologyHandle; localNodes: CARDINAL _ CountBase; throughNodes: LIST OF CarryThrough ~ NARROW[ circuit.properties.GetPropFromList[ carryThroughNodes] ]; linkCount: CARDINAL _ CountBase; subcellCount: CARDINAL _ CountBase; nodeStoppers: CARDINAL _ CountBase; output: IO.STREAM _ IO.ROS[]; currLine: TiogaFileOps.Ref _ NIL; <<-- Name generator customization>> CountSep: Rope.ROPE ~ "-"; CountBase: INTEGER ~ 1; portBase: Rope.ROPE ~ "p"; localBase: Rope.ROPE ~ "n"; stopperBase: Rope.ROPE ~ "tn"; throughPortBase: Rope.ROPE ~ "tp"; transBase: Rope.ROPE ~ "Q"; circuitBase: Rope.ROPE ~ "C"; <<-- First we must count how many times each symbol is used. The reason we do this is to avoid suffixing counts to symbols which are used only once.>> { count: INTEGER _ 17; FOR nl: LIST OF REF CircuitNode _ circuit.nodes, nl.rest WHILE nl # NIL DO count _ count.SUCC; ENDLOOP; Symbols _ SymTab.Create[mod~ count, case~ TRUE] }; FOR nl: LIST OF REF CircuitNode _ circuit.nodes, nl.rest WHILE nl # NIL DO signalName: REF SignalName ~ NARROW[nl.first.properties.GetPropFromList[ SpinifexAtoms.SignalName]]; IF signalName # NIL THEN { DisAmbiguate: PROCEDURE [ r: Rope.ROPE, use: REF ANY] RETURNS [nname: Rope.ROPE]~ { found: BOOLEAN; val: REF ANY; IF UsedSymbol[r] THEN { nameBase: Rope.ROPE ~ r.Cat[CountSep]; count: REF INTEGER; [found, val] _ Symbols.Fetch[r]; IF found THEN { WITH val SELECT FROM c: REF INTEGER => count _ c; n: REF CircuitNode => { prevName: REF Named ~ NARROW[n.properties.GetPropFromList[nodeName]]; count _ NEW[INTEGER]; [] _ Symbols.Store[r, count]; [nname, count^] _ FindUnique[base~ nameBase, start~ CountBase, val~ count]; n.properties _ n.properties.PutPropOnList[prop~ nodeName, val~ NEW[Named _ [nname, prevName.aliases]] ] }; al: LIST OF Rope.ROPE => { count _ NEW[INTEGER]; [] _ Symbols.Store[r, count]; [nname, count^] _ FindUnique[base~ nameBase, start~ CountBase, val~ count]; al.first _ nname }; ENDCASE => ERROR; count^ _ count^.SUCC } ELSE count _ NEW[INTEGER _ CountBase]; [nname, count^] _ FindUnique[base~ nameBase, start~ count^, val~ count]; } ELSE { [] _ Symbols.Store[r, use]; nname _ r }; }; r: Rope.ROPE ~ signalName.name; nameRec: REF Named; IF ignoreChildNames AND signalName.depth # 0 THEN LOOP; nl.first.properties _ nl.first.properties.PutPropOnList[prop~ nodeName, val~ (nameRec _ NEW[Named _ [DisAmbiguate[r, nl.first]]]) ]; <<-- Copy aliases.>> FOR al: REF SignalName _ signalName.alias, al.alias WHILE al # NIL DO IF ignoreChildNames AND al.depth # 0 THEN LOOP; nameRec.aliases _ CONS[ NIL, nameRec.aliases]; SELECT formatKey FROM SpinifexAtoms.thymePrint => nameRec.aliases.first _ al.name; -- Special last minute hack for Louis Monier at September 7, 1984 10:01:35 pm PDT. used to be the same as SpinifexAtoms.rosePrint case. SpinifexAtoms.rosePrint => nameRec.aliases.first _ DisAmbiguate[al.name, nameRec.aliases]; ENDCASE => ERROR; ENDLOOP } ENDLOOP; { <> logicalCellName: Rope.ROPE ~ Quote[CDDirectory.Name[cellObj]]; ports: CARDINAL _ CountBase; portCount: CARDINAL _ CountBase; PrintHead[logicalCellName]; FOR nl: LIST OF REF CircuitNode _ circuit.nodes, nl.rest WHILE nl # NIL DO IF nl.first.properties.GetPropFromList[ isPort] = isPort THEN { IF nl.first.properties.GetPropFromList[ nodeName] = NIL THEN { ports _ FindUnique[portBase, ports].count; nl.first.properties _ nl.first.properties.PutPropOnList[prop~ nodeName, val~ NEW[Port _ [ports]] ] }; PrintFormal[ QNodeName[nl.first], portCount, nl.first]; ports _ ports.SUCC; portCount _ portCount.SUCC; } ENDLOOP; { tpCount: INTEGER _ CountBase; tpPorts: CARDINAL _ 0; FOR ctl: LIST OF CarryThrough _ throughNodes, ctl.rest WHILE ctl # NIL DO tpName: Rope.ROPE; [tpName, tpCount] _ FindUnique[ throughPortBase, tpCount]; PrintFormal[ Quote[tpName], portCount + tpPorts]; ctl.first.numCT _ tpCount; tpCount _ tpCount.SUCC; tpPorts _ tpPorts.SUCC; ENDLOOP }; PrintStartBody[logicalCellName] }; <> FOR nl: LIST OF REF CircuitNode _ circuit.nodes, nl.rest WHILE nl # NIL DO IF nl.first.properties.GetPropFromList[ isPort] = NIL THEN { IF nl.first.properties.GetPropFromList[ nodeName] = NIL THEN { localNodes _ FindUnique[localBase, localNodes].count; nl.first.properties _ nl.first.properties.PutPropOnList[prop~ nodeName, val~ NEW[Local _ [localNodes]] ]; }; PrintLocalNode[nl.first]; localNodes _ localNodes.SUCC } ENDLOOP; <> FOR links: LIST OF REF NodeLinkage _ circuit.linkages, links.rest WHILE links # NIL DO PrintProc: REF ANY _ CDObjectProcs.FetchFurther[ p~links.first.source.ob.p, key~formatKey]; IF PrintProc # NIL THEN { qTName: Rope.ROPE; [qTName, linkCount] _ InstanceName[links.first.source, transBase, linkCount]; NARROW[ PrintProc, REF SpinifexOutput.LinkagePrintProc]^[ output, links.first, qTName, PrintNode]; linkCount _ linkCount.SUCC; } ELSE { output.Put[ IO.rope["Mystery object in Linkage List; ObjType ~ "], IO.atom[links.first.source.ob.p.objectType]]; }; AppendTiogaNode[output]; output _ output.ROS[]; ENDLOOP; <> FOR appls: CD.ApplicationList _ circuit.subcircuits, appls.rest WHILE appls # NIL DO actualsCount: CARDINAL _ CountBase; subcircuit: REF Circuit ~ NARROW[ CDProperties.GetPropFromObject[ from~appls.first.ob, prop~SpinifexAtoms.spinifex]]; subcircuitThroughNodes: LIST OF CarryThrough ~ NARROW[ subcircuit.properties.GetPropFromList[ carryThroughNodes]]; qCName: Rope.ROPE; [qCName, subcellCount] _ InstanceName[appls.first, circuitBase, subcellCount]; PrintInstanceHead[ qCName, CDDirectory.Name[appls.first.ob] ]; FOR nl: LIST OF REF CircuitNode _ subcircuit.nodes, nl.rest WHILE nl # NIL DO IF nl.first.properties.GetPropFromList[ isPort] # NIL THEN { parentNode: REF CircuitNode; IF circuit.mergeDirectory # NIL THEN { qual: LIST OF CD.ApplicationPtr; [node~ parentNode, rootQualifier~ qual] _ SpinifexCircuit.FindRootNode[ circuit~ circuit, subcircuitNode~ nl.first, qualifier~ LIST[appls.first]]; IF qual # NIL THEN parentNode _ NIL } ELSE parentNode _ NIL; IF parentNode # NIL THEN PrintActual[QNodeName[parentNode], QNodeName[nl.first], actualsCount] ELSE { <<-- Search throughNodes for nl.first.>> FOR ctl: LIST OF CarryThrough _ throughNodes, ctl.rest WHILE ctl # NIL DO IF ctl.first.key = nl.first AND ctl.first.merge.first.applChain.first = appls.first THEN { PrintActual[Quote[ Rope.Cat[throughPortBase, Convert.RopeFromInt[ ctl.first.numCT]]], QNodeName[nl.first], actualsCount]; EXIT }; REPEAT FINISHED => <<-- Generate `Node Stopper'>> PrintActual[PrintInvented[nl.first], QNodeName[nl.first], actualsCount]; ENDLOOP; }; actualsCount _ actualsCount.SUCC; } ENDLOOP; FOR subctl: LIST OF CarryThrough _ subcircuitThroughNodes, subctl.rest WHILE subctl # NIL DO <<-- 3 Possiblities: 1) node of circuit 2) throughNode of circuit 3) Need NodeStopper.>> <<-- for subctl.first.merge.first to end of subctl.first.merge find applChains whose key and chain match to chainTail if appl after chainTail = appls.first Then we have a matcher. IF chainTail matcher .rest.rest = NIL THEN Case1 ELSE Case2. If no matcher THEN case3.>> { FOR sml: MergeRecList _ subctl.first.merge, sml.rest WHILE sml # NIL DO appl2: LIST OF CD.ApplicationPtr _ sml.first.applChain; FOR appl1: LIST OF CD.ApplicationPtr _ subctl.first.merge.first.applChain, appl1.rest WHILE appl1 # subctl.first.chainTail DO IF appl2 = NIL OR appl1.first # appl2.first THEN EXIT; appl2 _ appl2.rest; REPEAT FINISHED => IF appl2 # NIL AND appl2.first = appls.first THEN { IF appl2.rest = NIL THEN <<-- Case 1) node of circuit.>> PrintActual[QNodeName[sml.first.becomes], Quote[ Rope.Cat[throughPortBase, Convert.RopeFromInt[ subctl.first.numCT]]], actualsCount] ELSE { <<-- Case 2) throughNode of circuit.>> FOR ctl: LIST OF CarryThrough _ throughNodes, ctl.rest WHILE ctl # NIL DO IF sml = ctl.first.merge THEN { PrintActual[Quote[ Rope.Cat[throughPortBase, Convert.RopeFromInt[ ctl.first.numCT]]], Quote[ Rope.Cat[throughPortBase, Convert.RopeFromInt[ subctl.first.numCT]]], actualsCount]; EXIT }; REPEAT FINISHED => ERROR ENDLOOP }; GOTO foundMatcher } ENDLOOP; REPEAT FINISHED => <<-- Case 3) Need NodeStopper.>> PrintActual[PrintInvented[subctl.first.key], Quote[ Rope.Cat[throughPortBase, Convert.RopeFromInt[ subctl.first.numCT]]], actualsCount]; ENDLOOP; EXITS foundMatcher => NULL }; actualsCount _ actualsCount.SUCC; ENDLOOP; subcellCount _ subcellCount.SUCC; PrintInstanceEnd[]; ENDLOOP; PrintBodyEnd[]; }; END.