<<>> <> <> <> <> DIRECTORY CardTab, CD, CDCommandOps, CDProperties, CDSequencer, CDSequencerExtras, IO, List, PriorityQueue, Rope, RefTab, SoftHdwAssembly, SoftHdwBasics, SoftHdwDelayPath, SoftHdwSimulate, SoftHdwCompiler, TerminalIO; SoftHdwDelayPathImpl: CEDAR PROGRAM IMPORTS CardTab, CDCommandOps, CDProperties, CDSequencerExtras, IO, PriorityQueue, RefTab, SoftHdwAssembly, SoftHdwBasics, SoftHdwSimulate, TerminalIO EXPORTS SoftHdwDelayPath = BEGIN OPEN SoftHdwDelayPath, SoftHdwBasics, SoftHdwAssembly; tempArrayPos: ArrayPosition _ NEW[ArrayPositionRec]; designToDelayNetworkKey: REF INT _ NEW[INT]; designToCurrentPathKey: REF INT _ NEW[INT]; CreateNetworkForSimulation: PUBLIC PROC [simulation: SoftHdwSimulate.Simulation] RETURNS [network: DelayNetwork] ~ { network _ CreateNetwork[simulation.base]; CDProperties.PutDesignProp[simulation.design, designToDelayNetworkKey, network]; }; CreateNetwork: PUBLIC PROC [array: SoftHdwBasics.ArrayBase] RETURNS [network: DelayNetwork] ~ { network _ NEW[DelayNetworkRec]; network.levelTable _ CardTab.Create[]; network.worstDelayTable _ PriorityQueue.Create[SortByDelay]; network.eventTable _ RefTab.Create[equal: ArrayPositionEqual, hash: ArrayPositionHash]; BuildCausalityGraph[array, network]; }; ResetNetwork: PUBLIC PROC [network: DelayNetwork] ~ { network.worstDelayTable _ PriorityQueue.Create[SortByDelay]; }; BuildCausalityGraph: PROC [array: SoftHdwBasics.ArrayBase, network: DelayNetwork] ~ { BuildDelayTerms: RefTab.EachPairAction ~ { <> pos: ArrayPosition _ NARROW[key]; SELECT pos.type FROM Output => BuildDelayTermsForGrain[pos, NARROW[val], array, network]; Long => BuildDelayTermsForLongLine[pos, NARROW[val], array, network]; RAMEven => BuildDelayTermsForRAM[pos, NARROW[val], array, network]; ENDCASE => ERROR; }; [] _ RefTab.Pairs[array.state.positionToEntity, BuildDelayTerms]; }; NameForType: PROC [type: NodeType] RETURNS [name: Rope.ROPE] ~ { RETURN[nodeNames[type]]; }; EventFromPos: PROC [key: ArrayPosition, type: NodeType, network: DelayNetwork] RETURNS [event: DelayEvent] ~ { <<... Look up an event of the given type for a grain at a given position. >> <> val: RefTab.Val; found: BOOL; tempArrayPos^ _ key^; tempArrayPos.type _ type; [found, val] _ RefTab.Fetch[network.eventTable, tempArrayPos]; IF found THEN { event _ NARROW[val]; RETURN[event]; } ELSE { newpos: ArrayPosition _ SoftHdwBasics.CopyArrayPosition[tempArrayPos]; event _ NEW[DelayEventRec _ [source: newpos]]; [] _ RefTab.Store[network.eventTable, newpos, event]; network.allDelayEvents _ CONS[event, network.allDelayEvents]; }; }; BuildDelayTermsForLongLine: PROC [pos: ArrayPosition, longLine: LongLine, array: ArrayBase, network: DelayNetwork] ~ { otherEvent: DelayEvent; FOR index: CARDINAL IN [0..longLine.size) DO longGrain: Grain _ longLine.grains[index]; IF longGrain.inputSelect=l THEN { lineEvent: DelayEvent _ EventFromPos[pos, Long, network]; otherEvent _ EventFromPos[longGrain.key, Input, network]; CreateDelayTerm[lineEvent, otherEvent, LToI]; }; IF longGrain.ORUToL THEN { lineEvent: DelayEvent _ EventFromPos[pos, Long, network]; otherEvent _ EventFromPos[longGrain.key, Output, network]; CreateDelayTerm[otherEvent, lineEvent, ORUToL]; }; ENDLOOP; }; BuildDelayTermsForRAM: PROC [pos: ArrayPosition, RAMArray: MinorArray, array: ArrayBase, network: DelayNetwork] ~{ << ...Create DelayTerms to drive all READ Data events (LeftDown Vertical) from all READ ADRRESS lines (RightUp Horizontal) . >> sourceEvent, destEvent: DelayEvent; <> <> <> IF RAMArray.RAMEven OR RAMArray.RAMOdd THEN { FOR grainIndex: INT IN [0..array.sizes.grain.x) DO tempArrayPos^ _ pos^; tempArrayPos.orientation _ Vertical; tempArrayPos.grain.y _ 0; tempArrayPos.grain.x _ grainIndex; destEvent _ EventFromPos[tempArrayPos, LeftDown, network]; FOR adrIndex: INT IN [0..array.sizes.grain.y) DO tempArrayPos^ _ pos^; tempArrayPos.grain.x _ 0; tempArrayPos.grain.y _ adrIndex; tempArrayPos.orientation _ Horizontal; sourceEvent _ EventFromPos[tempArrayPos, RightUp, network]; CreateDelayTerm[sourceEvent, destEvent, InputEnabled]; ENDLOOP; ENDLOOP; }; }; BuildDelayTermsForGrain: PROC [pos: ArrayPosition, grain: Grain, array: ArrayBase, network: DelayNetwork] ~{ << ...For each element of a grain {Output,Input,RightUp,LeftDown} these procedures create a new DelayEvent if needed, and create DelayTerms from any other DelayEvents which drive the element. >> BuildDelayTermForLeftDown[pos, grain, network]; BuildDelayTermForRightUp[pos, grain, network]; BuildDelayTermForInput[pos, grain, network]; BuildDelayTermForOutput[pos, grain, network]; }; BuildDelayTermForLeftDown: PROC [pos: ArrayPosition, grain: Grain, network: DelayNetwork] ~{ IF grain.rightUpGrain#NIL THEN { -- Create DelayTerm for LeftDown line otherGrain: Grain _ grain.rightUpGrain; IF otherGrain.LDToLD THEN { destEvent: DelayEvent _ EventFromPos[pos, LeftDown, network]; sourceEvent: DelayEvent _ EventFromPos[otherGrain.key, LeftDown, network]; CreateDelayTerm[sourceEvent, destEvent, LDToLD]; }; IF otherGrain.ORUToLD THEN { destEvent: DelayEvent _ EventFromPos[pos, LeftDown, network]; sourceEvent: DelayEvent _ EventFromPos[otherGrain.key, Output, network]; CreateDelayTerm[sourceEvent, destEvent, ORUToLD]; }; }; }; BuildDelayTermForRightUp: PROC [pos: ArrayPosition, grain: Grain, network: DelayNetwork] ~{ IF grain.leftDownGrain#NIL THEN { -- Create DelayTerm for RightUp line otherGrain: Grain _ grain.leftDownGrain; IF grain.RUToRU THEN { destEvent: DelayEvent _ EventFromPos[pos, RightUp, network]; sourceEvent: DelayEvent _ EventFromPos[otherGrain.key, RightUp, network]; CreateDelayTerm[sourceEvent, destEvent, RUToRU]; }; IF grain.OLDToRU THEN { destEvent: DelayEvent _ EventFromPos[pos, RightUp, network]; sourceEvent: DelayEvent _ EventFromPos[otherGrain.key, Output, network]; CreateDelayTerm[sourceEvent, destEvent, OLDToRU]; }; }; }; BuildDelayTermForInput: PROC [pos: ArrayPosition, grain: Grain, network: DelayNetwork] ~{ SELECT grain.inputSelect FROM none => NULL; oru => { destEvent: DelayEvent _ EventFromPos[pos, Input, network]; sourceEvent: DelayEvent _ EventFromPos[pos, Output, network]; CreateDelayTerm[sourceEvent, destEvent, ORUToI]; }; old => IF grain.leftDownGrain#NIL THEN { destEvent: DelayEvent _ EventFromPos[pos, Input, network]; sourceEvent: DelayEvent _ EventFromPos[grain.leftDownGrain.key, Output, network]; CreateDelayTerm[sourceEvent, destEvent, OLDToI]; }; ld => { destEvent: DelayEvent _ EventFromPos[pos, Input, network]; sourceEvent: DelayEvent _ EventFromPos[pos, LeftDown, network]; CreateDelayTerm[sourceEvent, destEvent, LDToI]; }; l => NULL; -- Long Lines are handled by BuildDelayTermsForLongLine ru => IF grain.leftDownGrain#NIL THEN { destEvent: DelayEvent _ EventFromPos[pos, Input, network]; sourceEvent: DelayEvent _ EventFromPos[grain.leftDownGrain.key, RightUp, network]; CreateDelayTerm[sourceEvent, destEvent, RUToI]; }; ENDCASE => ERROR; }; BuildDelayTermForOutput: PROC [pos: ArrayPosition, grain: Grain, network: DelayNetwork] ~{ IF grain.parallelInput THEN { destEvent: DelayEvent _ EventFromPos[pos, IF grain.flipFlop THEN Master ELSE Output, network]; sourceEvent: DelayEvent _ EventFromPos[pos, Input, network]; CreateDelayTerm[sourceEvent, destEvent, ParallelInput]; }; FOR grainIndex: INT IN [0..grain.size) DO IF grain.perpendicularGrains[grainIndex].inputEnabled AND grain.perpendicularGrains[grainIndex].grain#NIL THEN { destEvent: DelayEvent _ EventFromPos[pos, IF grain.flipFlop THEN Master ELSE Output, network]; sourceEvent: DelayEvent _ EventFromPos[grain.perpendicularGrains[grainIndex].grain.key, Input, network]; CreateDelayTerm[sourceEvent, destEvent, InputEnabled]; }; ENDLOOP; }; CreateDelayTerm: PROC [source: DelayEvent, dest: DelayEvent, type: NodeType] ~ { term: DelayTerm _ NEW[DelayTermRec _ [inputDelayEvent: source, outputDelayEvent: dest]]; termPosition: ArrayPositionRec _ NARROW[dest.source, ArrayPosition]^; sourcePosition: ArrayPosition _ NARROW[source.source]; term.delay _ DelayForTerm[type]; <> SELECT type FROM InputEnabled => { SELECT NARROW[dest.source, ArrayPosition].orientation FROM Vertical => { termPosition.grain.y _ sourcePosition.grain.y; }; Horizontal => { termPosition.grain.x _ sourcePosition.grain.x; }; ENDCASE => ERROR; }; ORUToLD, LDToLD => termPosition _ sourcePosition^; RUToI, ParallelInput, LDToI, OLDToI, ORUToI, OLDToRU, RUToRU, LToI => NULL; <> ORUToL => termPosition.minorArray _ sourcePosition.minorArray; ENDCASE => ERROR; termPosition.type _ type; term.source _ SoftHdwBasics.CopyArrayPositionRec[termPosition]; source.outputDelayTerms _ CONS[term, source.outputDelayTerms]; dest.inputDelayTerms _ CONS[term, dest.inputDelayTerms]; }; DelayForTerm: PROC [type: NodeType] RETURNS [INT] ~ { RETURN [SELECT type FROM ParallelInput, InputEnabled, RUToI, LDToI, OLDToI, ORUToI, OLDToRU, RUToRU, ORUToLD, LDToLD => 1, ENDCASE => 1 ]; }; <<>> MarkPrimaryInputs: PROC [network: DelayNetwork] ~ { <<... Marks all DelayEvents which have no inputDelayTerms as primary inputs.>> FOR events: DelayEvents _ network.allDelayEvents, events.rest WHILE events#NIL DO { event: DelayEvent _ events.first; IF event.inputDelayTerms=NIL THEN event.primaryInput _ TRUE; }; ENDLOOP; }; <> <<>> LevelizeDelayNetwork: PUBLIC PROC [network: DelayNetwork] ~ { FOR events: DelayEvents _ network.allDelayEvents, events.rest WHILE events#NIL DO [] _ LevelizeEvent[events.first]; ENDLOOP; BuildLevelTable[network]; }; <> LevelizeEvent: PROC [event: DelayEvent] RETURNS [level: INT] ~ { IF event.level#(-1) OR event.levelComputed THEN RETURN [event.level] ELSE { maxlevel: INT _ -1; event.levelComputed _ TRUE; FOR terms: DelayTerms _ event.inputDelayTerms, terms.rest WHILE terms#NIL DO term: DelayTerm _ terms.first; level: INT _ LevelizeEvent[term.inputDelayEvent]; maxlevel _ MAX[maxlevel, level]; ENDLOOP; event.levelComputed _ TRUE; level _ event.level _ IF (maxlevel>-1) THEN maxlevel+1 ELSE (IF event.primaryInput THEN 0 ELSE -1); }; }; SortByDelay: PriorityQueue.SortPred ~ { d1: DelayEvent _ NARROW[x]; d2: DelayEvent _ NARROW[y]; RETURN[d1.maxDelay > d2.maxDelay]; }; <> <> BuildLevelTable: PROC [network: DelayNetwork] ~ { table: CardTab.Ref _ CardTab.Create[]; maxlevel: INT _ 0; network.levelTable _ table; FOR events: DelayEvents _ network.allDelayEvents, events.rest WHILE events#NIL DO event: DelayEvent _ events.first; level: INT _ event.level; prevlist: DelayEvents _ NARROW[CardTab.Fetch[table,LOOPHOLE[level]].val]; newlist: DelayEvents _ CONS[event, prevlist]; maxlevel _ MAX[maxlevel,level]; [] _ CardTab.Store[table, LOOPHOLE[level], newlist]; ENDLOOP; network.maxLevel _ maxlevel; }; <> <> <<>> ComputeDelays: PUBLIC PROC [network: DelayNetwork] ~ { FOR level: INT IN [0..network.maxLevel] DO eventslist: DelayEvents _ NARROW[CardTab.Fetch[network.levelTable, LOOPHOLE[level]].val]; FOR events: DelayEvents _ eventslist, events.rest WHILE events#NIL DO event: DelayEvent _ events.first; ComputeEventDelay[event]; RecordMaxDelay[network, event]; ENDLOOP; ENDLOOP; }; ComputeSlack: PUBLIC PROC [network: DelayNetwork] ~ { FOR level: INT DECREASING IN [0..network.maxLevel] DO eventslist: DelayEvents _ NARROW[CardTab.Fetch[network.levelTable, LOOPHOLE[level]].val]; FOR events: DelayEvents _ eventslist, events.rest UNTIL events=NIL DO event: DelayEvent _ events.first; slack: INT _ 0; FOR terms: DelayTerms _ event.outputDelayTerms, terms.rest UNTIL terms=NIL DO term: DelayTerm _ terms.first; slack _ MAX[slack, term.outputDelayEvent.maxDelay-term.delay-event.maxDelay]; ENDLOOP; event.slack _ slack; ENDLOOP; ENDLOOP; }; RecordMaxDelay: PROC [network: DelayNetwork, event: DelayEvent] ~ { <> IF event.outputDelayTerms=NIL THEN { PriorityQueue.Insert[network.worstDelayTable, event]; }; IF (network.maxDelayEvent = NIL) OR (event.maxDelay > network.maxDelayEvent.maxDelay) THEN network.maxDelayEvent _ event; }; <> ComputeEventDelay: PROC [event: DelayEvent] ~ { maxdelay: INT _ 0; mindelay: INT _ LAST[INT]; zeroslack: DelayTerm; FOR terms: DelayTerms _ event.inputDelayTerms, terms.rest WHILE terms#NIL DO term: DelayTerm _ terms.first; delay: INT _ DelayTermDelay[term]; IF NOT term.blocked THEN { IF delay > maxdelay THEN zeroslack _ term; maxdelay _ MAX[maxdelay, delay]; mindelay _ MIN[mindelay, delay]; }; ENDLOOP; event.minDelay _ mindelay; event.maxDelay _ maxdelay; event.zeroSlackTerm _ zeroslack; }; DelayTermDelay: PROC [term: DelayTerm] RETURNS [delay: INT] ~ { inputEvent: DelayEvent _ term.inputDelayEvent; RETURN[term.delay + inputEvent.maxDelay]; }; <> <> ReportCriticalPath: PUBLIC PROC [network: DelayNetwork, eventPrintFn: EventPrintFn, termPrintFn: TermPrintFn] ~ { worstEvent: DelayEvent _ NARROW[PriorityQueue.Remove[network.worstDelayTable]]; TracePath[worstEvent, eventPrintFn, termPrintFn]; }; TracePath: PUBLIC PROC [event: DelayEvent, eventPrintFn: EventPrintFn, termPrintFn: TermPrintFn] ~ { <<...Prints out a delay path by traing an event back, following the zero slack pointers, until an event with no input terms is reached. >> nextevent: DelayEvent; TerminalIO.PutF["\n--Delay Path min %d, max %d:", IO.int[event.minDelay], IO.int[event.maxDelay]]; FOR term: DelayTerm _ event.zeroSlackTerm, nextevent.zeroSlackTerm WHILE term#NIL DO eventPrintFn[term.outputDelayEvent]; <> nextevent _ term.inputDelayEvent; ENDLOOP; eventPrintFn[nextevent]; }; SummarizePath: PUBLIC PROC [event: DelayEvent, eventPrintFn: EventPrintFn] ~ { <<...Just print out the total path delays.>> nextevent: DelayEvent; TerminalIO.PutF["\n--Delay Path min %d, max %d:", IO.int[event.minDelay], IO.int[event.maxDelay]]; TerminalIO.PutF["Output (Final) Event: "]; PrintEvent[event]; TerminalIO.PutF["Start Event: "]; FOR term: DelayTerm _ event.zeroSlackTerm, nextevent.zeroSlackTerm WHILE term#NIL DO nextevent _ term.inputDelayEvent; ENDLOOP; eventPrintFn[nextevent]; }; MakeDelayPositionPath: PUBLIC PROC [event: DelayEvent] RETURNS [ArrayPositions] ~ { <<... Traces an event back through the zero slack terms, creating a list of the array positions>> <> nextevent: DelayEvent _ event; pathlist: ArrayPositions _ NIL; FOR term: DelayTerm _ event.zeroSlackTerm, nextevent.zeroSlackTerm WHILE term#NIL DO { outEvent: DelayEvent _ term.outputDelayEvent; pathlist _ CONS[NARROW[outEvent.source], pathlist]; pathlist _ CONS[NARROW[term.source], pathlist]; nextevent _ term.inputDelayEvent; }; ENDLOOP; pathlist _ CONS[NARROW[nextevent.source], pathlist]; RETURN[pathlist]; }; MakeColoredDelayPositionPath: PUBLIC PROC [event: DelayEvent] RETURNS [ColoredArrayPositions] ~ { <<... Traces an event back through the zero slack terms, creating a list of colored array positions>> <> pathlist: ArrayPositions _ MakeDelayPositionPath[event]; cpathlist: ColoredArrayPositions _ NIL; FOR poslist: ArrayPositions _ pathlist, poslist.rest WHILE poslist#NIL DO cpathlist _ CONS[[color: red, position: poslist.first], cpathlist]; ENDLOOP; RETURN[cpathlist]; }; PrintEvent: PUBLIC PROC [event: DelayEvent] ~ { zeroslackdelay: INT _ 0; IF event#NIL THEN { IF event.zeroSlackTerm#NIL THEN zeroslackdelay _ event.zeroSlackTerm.delay; TerminalIO.PutF["\nEvent: %g delay %g (%g)", IO.rope[ArrayPositionToRope[NARROW[event.source]]], IO.int[event.maxDelay],IO.int[zeroslackdelay]]; }; }; PrintTerm: PUBLIC PROC [term: DelayTerm] ~ { TerminalIO.PutF["\n Term: %g delay %g", IO.rope[ArrayPositionToRope[NARROW[term.source]]], IO.int[term.delay]]; }; PrintGenericEvent: PUBLIC PROC [event: DelayEvent] ~ { zeroslackdelay: INT _ 0; IF event#NIL THEN { IF event.zeroSlackTerm#NIL THEN zeroslackdelay _ event.zeroSlackTerm.delay; <> TerminalIO.PutF["\nEvent: delay %g (%g)", IO.int[event.maxDelay],IO.int[zeroslackdelay]]; }; }; PrintGenericTerm: PUBLIC PROC [term: DelayTerm] ~ { <> TerminalIO.PutF["\n Term: delay %g", IO.int[term.delay]]; }; TimingAnalyze: PUBLIC PROC [simulation: SoftHdwSimulate.Simulation] RETURNS [network: DelayNetwork] ~ { TerminalIO.PutF["\nCreating Timing Analysis Network..."]; network _ CreateNetworkForSimulation[simulation]; MarkPrimaryInputs[network]; LevelizeDelayNetwork[network]; TerminalIO.PutF["\nDoing Timing Analysis."]; ComputeDelays[network]; TerminalIO.PutF["\nLongest Critical Path:"]; ReportCriticalPath[network, PrintEvent, PrintTerm]; }; SoftHdwTimingAnalyze: PROC [command: CDSequencer.Command] = { <<... If a network already exists, just recompute the delays, else create a new one.>> simulation: SoftHdwSimulate.Simulation _ NARROW[CDProperties.GetDesignProp[command.design, SoftHdwSimulate.designToSimulationKey]]; IF simulation#NIL THEN { network: DelayNetwork _ NARROW[CDProperties.GetDesignProp[command.design, designToDelayNetworkKey]]; IF network=NIL THEN { TerminalIO.PutF["\nCreating new Network for this design..."] ; network _ CreateNetworkForSimulation[simulation]; MarkPrimaryInputs[network]; LevelizeDelayNetwork[network]; }; <> network.worstDelayTable _ PriorityQueue.Create[SortByDelay]; ComputeDelays[network]; TerminalIO.PutF["\nTiming Analysis Done."]; } ELSE TerminalIO.PutF["\nNo simulation found for this design!"]; }; PrintCriticalPath: PROC [command: CDSequencer.Command] = { simulation: SoftHdwSimulate.Simulation _ NARROW[CDProperties.GetDesignProp[command.design, SoftHdwSimulate.designToSimulationKey]]; IF simulation#NIL THEN { currentPath: DelayEvent _ NARROW[CDProperties.GetDesignProp[command.design, designToCurrentPathKey]]; IF currentPath#NIL THEN { TerminalIO.PutF["\nCurrent Path:"]; TracePath[currentPath, PrintEvent, PrintTerm]; } ELSE TerminalIO.PutF["\nThere is no current critical path for this design."]; } ELSE TerminalIO.PutF["\nNo simulation found for this design!"]; }; HighlightCriticalPath: PROC [command: CDSequencer.Command]~ { simulation: SoftHdwSimulate.Simulation _ NARROW[CDProperties.GetDesignProp[command.design, SoftHdwSimulate.designToSimulationKey]]; IF simulation=NIL THEN TerminalIO.PutF["\nNo simulation found for this design!"] ELSE { network: DelayNetwork _ NARROW[CDProperties.GetDesignProp[command.design, designToDelayNetworkKey]]; IF network=NIL THEN TerminalIO.PutF["\nNo network for this design!"] ELSE { worstEvent: DelayEvent _ NARROW[PriorityQueue.Remove[network.worstDelayTable]]; <> CDProperties.PutDesignProp[simulation.design, designToCurrentPathKey, worstEvent]; IF worstEvent.level = 0 THEN TerminalIO.PutF["\nThis delay path ends at level 0; You have probably finished looking at all the interesting paths."] ELSE { posList: ColoredArrayPositions _ MakeColoredDelayPositionPath[worstEvent]; SummarizePath[worstEvent, PrintEvent]; SoftHdwAssembly.HighlightDesign[command.design, simulation.sizes, NIL]; SoftHdwAssembly.HighlightDesign[command.design, simulation.sizes, posList, NIL, "Critical Path"]; }; }; }; }; BlockPath: PROC [command: CDSequencer.Command] = { <<... Find the Event which the user clicked on, and toggle the blocked flag of all the terms which it sources.>> FindEvent: PROC [key: ArrayPosition, network: DelayNetwork] RETURNS [event: DelayEvent, found: BOOL] ~ { val: RefTab.Val; [found, val] _ RefTab.Fetch[network.eventTable, key]; IF found THEN { event _ NARROW[val]; RETURN[event, TRUE]; } ELSE RETURN [NIL,FALSE]; }; BlockPathForEvent: PROC [event: DelayEvent] ~ { <<...Toggle all outputDelayTerms blocked flag.>> term: DelayTerm; IF event.outputDelayTerms#NIL THEN { FOR terms: DelayTerms _ event.outputDelayTerms, terms.rest WHILE terms#NIL DO term _ terms.first; term.blocked _ NOT term.blocked; ENDLOOP; IF term.blocked THEN TerminalIO.PutF["\nDelay Terms From %g Blocked.", IO.rope[ArrayPositionToRope[NARROW[event.source]]]] ELSE TerminalIO.PutF["\nDelay Terms From %g Unblocked.", IO.rope[ArrayPositionToRope[NARROW[event.source]]]]; }; }; simulation: SoftHdwSimulate.Simulation _ NARROW[CDProperties.GetDesignProp[command.design, SoftHdwSimulate.designToSimulationKey]]; ambiguous: BOOL; position: SoftHdwBasics.ArrayPosition; IF simulation=NIL THEN TerminalIO.PutF["\nNo simulation found for this design!"] ELSE { network: DelayNetwork _ NARROW[CDProperties.GetDesignProp[command.design, designToDelayNetworkKey]]; IF network=NIL THEN TerminalIO.PutF["\nNo network for this design!"] ELSE { [ambiguous, position] _ SoftHdwAssembly.CDToArrayPosition[simulation.sizes, simulation.program.coordinates, command.sPos]; IF ambiguous THEN TerminalIO.PutRope["\nAmbiguous position"] ELSE { event: DelayEvent; found: BOOL; <> [event,found] _ FindEvent[position, network]; IF NOT found THEN TerminalIO.PutF["\nNo Event found at that position!"] ELSE BlockPathForEvent[event]; }; }; }; }; InitCDCommands: PROC ~ { CDCommandOps.RegisterWithMenu[$SpecialMenu, "Timing Analyze", "Timing Analyze this design.", $SoftHdwTimingAnalyze, SoftHdwTimingAnalyze]; CDCommandOps.RegisterWithMenu[$SpecialMenu, "Show Critical Path", "Highlights a critical path in the current design", $SoftHdwHighlightCriticalPath, HighlightCriticalPath]; CDCommandOps.RegisterWithMenu[$SpecialMenu, "Print Last Path", "Prints the current critical path in the current design", $SoftHdwPrintCriticalPath, PrintCriticalPath]; CDSequencerExtras.RegisterCommand[key: $RosemaryPlotSelectedWires, proc: BlockPath, queue: doQueue]; }; <> TimingAnalyzeFlatCell: PUBLIC PROC [flatCell: SoftHdwCompiler.FlatCell] RETURNS [network: DelayNetwork] ~ { TerminalIO.PutF["\nCreating Timing Analysis Network..."]; network _ CreateNetworkFromFlatCell[flatCell]; MarkPrimaryInputs[network]; LevelizeDelayNetwork[network]; TerminalIO.PutF["\nDoing Timing Analysis."]; ComputeDelays[network]; TerminalIO.PutF["\nLongest Critical Path:"]; ReportCriticalPath[network, PrintGenericEvent, PrintGenericTerm]; }; CreateNetworkFromFlatCell: PUBLIC PROC [flatCell: SoftHdwCompiler.FlatCell] RETURNS [network: DelayNetwork] ~ { EventFromPrim: PROC [prim: SoftHdwCompiler.Primitive] RETURNS [event: DelayEvent] ~ { <> <> <> IF prim=NIL THEN { event _ NEW[DelayEventRec]; network.allDelayEvents _ CONS[event,network.allDelayEvents]; } ELSE { val: RefTab.Val; found: BOOL; [found, val] _ RefTab.Fetch[network.eventTable, prim]; IF found THEN { event _ NARROW[val]; RETURN[event]; } ELSE { event _ NEW[DelayEventRec]; [] _ RefTab.Store[network.eventTable, prim, event]; network.allDelayEvents _ CONS[event,network.allDelayEvents]; }; }; }; BuildDelayEvents: RefTab.EachPairAction ~ { CreateDelayTerm: PROC [source, dest: DelayEvent, delay: INT] ~ { term: DelayTerm _ NEW[DelayTermRec _ [inputDelayEvent: source, outputDelayEvent: dest, source: prim]]; term.delay _ delay; source.outputDelayTerms _ CONS[term, source.outputDelayTerms]; dest.inputDelayTerms _ CONS[term, dest.inputDelayTerms]; }; <> prim: SoftHdwCompiler.Primitive _ NARROW[val]; outputEvent: DelayEvent _ NIL; IF prim.flatClock=NIL THEN outputEvent _ EventFromPrim[prim] ELSE { outputEvent _ NEW[DelayEventRec]; network.allDelayEvents _ CONS[outputEvent, network.allDelayEvents]; }; IF outputEvent.source#NIL THEN ERROR; outputEvent.source _ prim; FOR input: INT IN [0..prim.size) DO inputEvent: DelayEvent _ EventFromPrim[prim[input].source]; CreateDelayTerm[inputEvent, outputEvent, 1]; ENDLOOP; }; network _ NEW[DelayNetworkRec]; network.levelTable _ CardTab.Create[]; network.worstDelayTable _ PriorityQueue.Create[SortByDelay]; network.eventTable _ RefTab.Create[]; [] _ RefTab.Pairs[flatCell.wires, BuildDelayEvents]; }; <> InitCDCommands[]; END.