<> <> <> <> <> <> <> <> DIRECTORY Basics, Buttons, ChoiceButtons, Commander, CommandTool, Containers, Convert, Core, CoreOps, CoreProperties, --EGlas,-- FS, ICTest, IO, IMSTester, MessageWindow, Ports, Rope, RosemaryUser, Rules, RuntimeError, SymTab, TypeScript, ViewerClasses, ViewerIO, ViewerOps, ViewerTools; ICTestImpl: CEDAR PROGRAM IMPORTS Basics, Buttons, ChoiceButtons, Commander, CommandTool, Containers, Convert, CoreOps, CoreProperties, --EGlas,-- FS, IO, IMSTester, MessageWindow, Ports, Rope, Rules, RuntimeError, SymTab, TypeScript, ViewerIO, ViewerOps, ViewerTools EXPORTS ICTest = BEGIN OPEN ICTest; maxErrors: NAT _ 40; testNamesTable: SymTab.Ref _ SymTab.Create[]; ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; Button: TYPE = Buttons.Button; signalNameLength: CARDINAL = 6; --IMS signal name length restriction groupNameLength: CARDINAL = 9; --IMS group name name length restriction PodTimingGroups: TYPE = IMSTester.PodTimingGroups; Board: TYPE = IMSTester.Board; PodTiming: TYPE = IMSTester.PodTiming; Channel: TYPE = IMSTester.Channel; PodChannel: TYPE = IMSTester.PodChannel; Cycle: TYPE = IMSTester.Cycle; Jumps: TYPE = IMSTester.Jumps; AbortDieSignal: PUBLIC ERROR = CODE; AbortWaferSignal: PUBLIC ERROR = CODE; InterruptSignal: PUBLIC ERROR = CODE; Test: TYPE = REF TestRec; TestRec: TYPE = RECORD[proc: TestProc, start: Cycle, length: Cycle]; Stop: TYPE = {dont, abortDie, abortWafer, interrupt}; DiePosition: TYPE = RECORD [x,y: NAT]; MapRec: TYPE = RECORD[b: Board, p: PodChannel, port: Ports.Port, index: NAT]; BoardToSlot: TYPE = ARRAY Board OF RECORD[slot: NAT, programable: BOOL]; ForceSubGroupsRec: TYPE = RECORD[fullName: ROPE, subGroups: IMSTester.ForceGroups]; AcquireSubGroupsRec: TYPE = RECORD[fullName: ROPE, subGroups: IMSTester.AcquireGroups]; periodChangeProc: ROPE = "periodChangeProc"; Handle: TYPE = REF ICTestRec; ICTestRec: PUBLIC TYPE = RECORD [ <<-- Standard button state -->> waferFile: Viewer _ NIL, run: Viewer _ NIL, wafer: Viewer _ NIL, die: Viewer _ NIL, memCycle: Viewer _ NIL, startTest: Button _ NIL, period: Viewer _ NIL, group: Viewer _ NIL, delay: Viewer _ NIL, width: Viewer _ NIL, sample: Viewer _ NIL, hiDrive: Viewer _ NIL, loDrive: Viewer _ NIL, threshold: Viewer _ NIL, enableStepper: BOOL _ FALSE, enableTester: BOOL _ FALSE, enableSimulation: BOOL _ FALSE, singleCycle: BOOL _ FALSE, loopTest: BOOL _ FALSE, <<-- Test buttons state-->> testButtonContainer: Viewer _ NIL, testButtonList: LIST OF Button _ NIL, testProcsTable: SymTab.Ref _ NIL, currentTestProc: ROPE _ NIL, <<-- Typescript -->> typeScriptContainer: Viewer _ NIL, outStream: IO.STREAM _ NIL, lastPeriod: Period _ 50, wDir: ROPE _ NIL, firstFreeCycle: Cycle _ 0, currentDie: DiePosition, -- die to return to upon "Continue" button stop: Stop _ dont, -- state of control buttons backupToken: IO.STREAM, -- temp for file stream parsing testInProgress: BOOL _ FALSE, -- button monitor inStream: IO.STREAM _ NIL, port: Ports.Port _ NIL, cellType: Core.CellType _ NIL, clockAName: ROPE _ NIL, clockBName: ROPE _ NIL, clockAPort: Ports.Port _ NIL, clockBPort: Ports.Port _ NIL, forceGroups: IMSTester.ForceGroups _ NIL, acquireGroups: IMSTester.AcquireGroups _ NIL, forceMap: LIST OF MapRec _ NIL, acquireMap: LIST OF MapRec _ NIL, cycle: Cycle _ 0, buffer: IMSTester.Buffer _ NIL, nullCycleData: IMSTester.CycleData _ NIL, forceNamesTab: SymTab.Ref _ NIL, acquireNamesTab: SymTab.Ref _ NIL, groups: Groups _ NIL, assignments: Assignments _ NIL, forceBoardToSlot: REF BoardToSlot _ NEW[BoardToSlot], acquireBoardToSlot: REF BoardToSlot _ NEW[BoardToSlot], forceSubGroups: LIST OF ForceSubGroupsRec, acquireSubGroups: LIST OF AcquireSubGroupsRec ]; entryHeight: NAT = 15; -- how tall to make each line of items entryVSpace: NAT = 4; -- vertical leading space between lines pointsPerInch: NAT = 72; -- horizontal space for text ropes pointsPerHalfInch: NAT = 36; -- horizontal space for text ropes col1: NAT = 0*pointsPerHalfInch; -- horizontal space to first column of buttons col2: NAT = 4*pointsPerHalfInch; -- second column col3: NAT = 7*pointsPerHalfInch; -- third column col4: NAT = 10*pointsPerHalfInch; -- fourth column col5: NAT = 13*pointsPerHalfInch; -- fifth column Column: TYPE = NAT [0..5); ColumnStart: ARRAY Column OF NAT = [col1, col2, col3, col4, col5]; MakeStandardViewer: PUBLIC PROC [testName: ROPE, cellType: Core.CellType, clockAName: ROPE, clockBName: ROPE _ NIL, groups: Groups, assignments: Assignments, period: Period] = { Button: PROC [name: ROPE, col: NAT, proc: Buttons.ButtonProc, fork: BOOL _ TRUE] = { [] _ Buttons.Create[info: [name: name, wx: col, wy: height, ww: 0, wh: entryHeight, parent: standardButtons], clientData: h, proc: proc, fork: fork]; }; Prompt: PROC [name: ROPE, col: NAT, contents: ROPE _ NIL] RETURNS [Viewer] = { RETURN[ChoiceButtons.BuildTextPrompt[standardButtons, col, height, name, contents, NIL, 1*pointsPerHalfInch].textViewer]; }; h: Handle _ NEW[ICTestRec]; rule: Rules.Rule; typeScript: Viewer; height: CARDINAL _ 0; viewer: Viewer _ Containers.Create[[name: Rope.Concat["IC Test Tool - ", testName], scrollable: FALSE]]; <<***Standard Buttons***>> standardButtons: Viewer _ Containers.Create[[scrollable: FALSE, parent: viewer, border: FALSE]]; Containers.ChildXBound[viewer, standardButtons]; Containers.ChildYBound[viewer, standardButtons]; h.wDir _ CommandTool.CurrentWorkingDirectory[]; h.waferFile _ ChoiceButtons.BuildTextPrompt[standardButtons, col1, height, "Wafer File:", "SingleDie.dat", NIL, 7*pointsPerInch].textViewer; height _ height + entryHeight + entryVSpace; h.run _ Prompt["Run:", col1]; h.startTest _ Buttons.Create[info: [name: "Start Test", wx: col2, wy: height, wh: entryHeight, parent: standardButtons], clientData: h, proc: StartTest, fork: TRUE]; Button["Abort Die", col3, AbortDie, FALSE]; Button["Single Cycle", col4, SingleCycle]; h.period _ Prompt["Period (nS):", col5, IO.PutR1[IO.int[period]]]; h.lastPeriod _ period; height _ height + entryHeight + entryVSpace; h.wafer _ Prompt["Wafer:", col1]; Button["Enable Tester", col2, EnableTester]; Button["Abort Wafer", col3, AbortWafer, FALSE]; Button["Loop Test", col4, LoopTest]; Button["Dump Memory", col5, DumpMemory]; height _ height + entryHeight + entryVSpace; h.die _ Prompt["Die:", col1]; Button["Get Memory", col2, GetMemory]; Button["Abort Test", col3, AbortTest, FALSE]; Button["Stop!", col4, StopLoop]; Button["Dump Errors", col5, DumpErrors]; height _ height + entryHeight + entryVSpace; h.memCycle _ Prompt["Mem Cycle:", col1, "0"]; Button["Get Errors", col2, GetErrors]; Button["Enable Stepper", col3, EnableStepper]; <> <> <<>> height _ height + entryHeight + entryVSpace/2+1; rule _ Rules.Create[[parent: standardButtons, wy: height, wh: 2]]; Containers.ChildXBound[standardButtons, rule]; height _ height + entryVSpace; Button["Get Parameters", col1+2, GetParameters]; Button["Set Parameters", col2, SetParameters]; h.delay _ Prompt["Delay:", col3, "?"]; h.width _ Prompt["Width:", col4, "?"]; h.sample _ Prompt["Sample:", col5, "?"]; height _ height + entryHeight + entryVSpace; h.group _ ChoiceButtons.BuildTextPrompt[standardButtons, col1, height, "Group:", "", NIL, 2*pointsPerInch].textViewer; h.hiDrive _ Prompt["HiDrive:", col3, "?"]; h.loDrive _ Prompt["LoDrive:", col4, "?"]; h.threshold _ Prompt["Threshold:", col5, "?"]; height _ height + entryHeight + entryVSpace/2+1; rule _ Rules.Create[[parent: standardButtons, wy: height, wh: 2]]; Containers.ChildXBound[standardButtons, rule]; height _ height + 2; <<***Test Buttons***>> h.testButtonContainer _ Containers.Create[[wy: height, wh: entryVSpace, scrollable: FALSE, parent: viewer, border: FALSE]]; Containers.ChildXBound[viewer, h.testButtonContainer]; height _ height + entryVSpace; <<***TypeScript***>> h.typeScriptContainer _ Containers.Create[[wy: height, scrollable: FALSE, parent: viewer, border: FALSE]]; Containers.ChildXBound[viewer, h.typeScriptContainer]; Containers.ChildYBound[viewer, h.typeScriptContainer]; rule _ Rules.Create[[parent: h.typeScriptContainer, wy: 0, wh: 2]]; Containers.ChildXBound[h.typeScriptContainer, rule]; typeScript _ ViewerOps.CreateViewer[flavor: $TypeScript, info:[parent: h.typeScriptContainer, wy: 2, ww: 7*pointsPerInch, wh: 6*pointsPerInch, scrollable: TRUE, border: FALSE]]; Containers.ChildXBound[h.typeScriptContainer, typeScript]; Containers.ChildYBound[h.typeScriptContainer, typeScript]; [ , h.outStream] _ ViewerIO.CreateViewerStreams[name: "ICTestTS", viewer: typeScript]; TypeScript.ChangeLooks[typeScript, 'f]; Commander.Register[key: "///Commands/Name", proc: LookUpName, doc: "Map an IMS signal name to/from the shortened version", clientData: h]; h.testProcsTable _ SymTab.Create[]; [] _ SymTab.Store[x: testNamesTable, key: testName, val: h]; h.cellType _ cellType; h.groups _ groups; h.assignments _ assignments; h.clockAName _ clockAName; h.clockBName _ clockBName; ViewerOps.OpenIcon[icon: viewer, bottom: FALSE]; }; RegisterTestProc: PUBLIC PROC [testName: ROPE, procName: ROPE, proc: TestProc, autoLoad: BOOL _ FALSE] = { h: Handle _ NIL; ref: REF _ NIL; found: BOOL _ FALSE; row, column: CARDINAL; count: CARDINAL _ 0; button: Button _ NIL; [found, ref] _ SymTab.Fetch[testNamesTable, testName]; IF NOT found THEN ERROR; --couldn't find the tester handle, probably bad testName h _ NARROW[ref]; IF NOT SymTab.Fetch[h.testProcsTable, procName].found THEN { --add a new button FOR l: LIST OF Button _ h.testButtonList, l.rest WHILE l#NIL DO count _ count+1 ENDLOOP; row _ count/(LAST[Column]+1); column _ count MOD (LAST[Column]+1); IF column=FIRST[Column] THEN { --make a new row ViewerOps.MoveViewer[h.testButtonContainer, h.testButtonContainer.wx, h.testButtonContainer.wy, h.testButtonContainer.ww, h.testButtonContainer.wh+entryHeight+entryVSpace]; ViewerOps.MoveViewer[h.typeScriptContainer, h.typeScriptContainer.wx, h.typeScriptContainer.wy+entryHeight+entryVSpace, h.typeScriptContainer.ww, h.typeScriptContainer.wh]; }; button _ Buttons.Create[info: [name: procName, wx: ColumnStart[column]+2, wy: row*(entryHeight+entryVSpace)+entryVSpace, ww: 0, wh: entryHeight, parent: h.testButtonContainer, border: TRUE], clientData: h, proc: TestButtonProc]; h.testButtonList _ CONS[button, h.testButtonList]; }; [] _ SymTab.Store[x: h.testProcsTable, key: procName, val: NEW[TestRec _ [proc, 0, 0]]]; IF autoLoad AND NOT h.testInProgress THEN { IF h.loopTest THEN Message["Can't auto load. LoopTest is TRUE"] ELSE { oldTest: ROPE _ h.currentTestProc; h.currentTestProc _ procName; h.stop _ dont; IF h.inStream # NIL THEN IO.Close[h.inStream]; --just in case last test was aborted Init[h]; DoTest[h ! InterruptSignal => CONTINUE]; Cleanup[h]; h.currentTestProc _ oldTest; }; }; }; RegisterPeriodChangeProc: PUBLIC PROC [testName: ROPE, proc: PeriodChangeProc] = { h: Handle _ NIL; ref: REF _ NIL; found: BOOL _ FALSE; [found, ref] _ SymTab.Fetch[testNamesTable, testName]; IF NOT found THEN ERROR; --couldn't find the tester handle, probably bad testName h _ NARROW[ref]; [] _ SymTab.Store[x: h.testProcsTable, key: periodChangeProc, val: NEW[PeriodChangeProc _ proc]]; }; TestButtonProc: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; selectedButton: ViewerClasses.Viewer _ NARROW[parent]; FOR l: LIST OF Button _ h.testButtonList, l.rest WHILE l#NIL DO Buttons.SetDisplayStyle[l.first, IF l.first = selectedButton THEN $WhiteOnBlack ELSE $BlackOnWhite]; ENDLOOP; h.currentTestProc _ selectedButton.name; }; DoTest: PROC [h: Handle] = { NextToken: PROC [h: Handle] RETURNS [s: IO.STREAM] = { s _ IF h.backupToken # NIL THEN h.backupToken ELSE IO.RIS[IO.GetTokenRope[h.inStream].token]; h.backupToken _ NIL; }; BackupToken: PROC [s: IO.STREAM] RETURNS [] = { h.backupToken _ s; }; NextRun: PROC [h: Handle] RETURNS [done: BOOLEAN _ FALSE] = { c: CHAR; s: IO.STREAM; IF h.stop # interrupt THEN { WHILE NOT done DO s _ NextToken[h ! IO.EndOfStream => {done _ TRUE; CONTINUE}]; IF NOT done THEN SELECT (c _ IO.PeekChar[s]) FROM 'r, 'R => EXIT; 'w, 'W => NULL; 'd, 'D => NULL; IN ['0..'9] => NULL; ENDCASE => {Message["Error: Bad token in data file, aborting test"]; done _ TRUE}; ENDLOOP; IF NOT done THEN { ViewerTools.SetContents[h.run, IO.GetTokenRope[NextToken[h ! IO.EndOfStream => {done _ TRUE; CONTINUE}]].token]; IO.PutF[h.outStream, "\n%g: Run %g, ", IO.rope[h.currentTestProc], IO.rope[ViewerTools.GetContents[h.run]]]; }; IF done THEN { IO.Close[h.inStream]; IF NOT h.loopTest THEN h.testInProgress _ FALSE; }; }; }; NextWafer: PROC [h: Handle] RETURNS [done: BOOLEAN _ FALSE] = { c: CHAR; s: IO.STREAM; IF h.stop # interrupt THEN { WHILE NOT done DO s _ NextToken[h ! IO.EndOfStream => {done _ TRUE; CONTINUE}]; IF NOT done THEN SELECT (c _ IO.PeekChar[s]) FROM 'r, 'R => {done _ TRUE; BackupToken[s]}; 'w, 'W => EXIT; 'd, 'D => NULL; IN ['0..'9] => NULL; ENDCASE => {Message["Error: Bad token in data file, aborting test"]; done _ TRUE}; ENDLOOP; IF NOT done THEN { ViewerTools.SetContents[h.wafer, IO.GetTokenRope[NextToken[h ! IO.EndOfStream => {done _ TRUE; CONTINUE}]].token]; IO.PutF[h.outStream, "Wafer %g, ", IO.rope[ViewerTools.GetContents[h.wafer]]]; IF h.enableStepper THEN { <> <> } ; }; }; }; NextDie: PROC [h: Handle] RETURNS [done: BOOLEAN _ FALSE] = { Eval: RosemaryUser.TestEvalProc = { CheckStop[h]; IF (h.clockAPort=NIL AND h.clockBPort=NIL) OR (h.clockAPort#NIL AND Ports.GB[h.clockAPort]) OR (h.clockBPort#NIL AND Ports.GB[h.clockBPort]) THEN { ForceDataToBuffer[h]; CompareDataToBuffer[h]; IF h.singleCycle THEN { BufferToIMS[h: h, cycles: 1, start: 0, halt: 0]; IMSTester.Start[]; } ELSE { h.cycle _ h.cycle+1; IF h.cycle = h.buffer.cycle THEN NewBuffer[h]; }; }; }; count: LONG CARDINAL; c: CHAR; s: IO.STREAM; IF h.stop # interrupt THEN { WHILE NOT done DO s _ NextToken[h ! IO.EndOfStream => {done _ TRUE; CONTINUE}]; IF NOT done THEN SELECT (c _ IO.PeekChar[s]) FROM 'r, 'R => {done _ TRUE; BackupToken[s]}; 'w, 'W => {done _ TRUE; BackupToken[s]}; 'd, 'D => h.currentDie.y _ IO.GetInt[NextToken[h ! IO.EndOfStream => {done _ TRUE; CONTINUE}]]; IN ['0..'9] => EXIT; ENDCASE => {Message["Error in data file, aborting test"]; done _ TRUE}; ENDLOOP; IF NOT done THEN { h.currentDie.x _ IO.GetInt[s]; ViewerTools.SetContents[h.die, IO.PutFR["%g,%g", IO.int[h.currentDie.y], IO.int[h.currentDie.x]]]; IO.PutF[h.outStream, "Die %g,%g ", IO.int[h.currentDie.y], IO.int[h.currentDie.x]]; }; }; IF NOT done THEN { h.stop _ dont; h.testInProgress _ TRUE; IF h.enableStepper THEN { <> <> <> }; Ports.RenewPort[h.cellType, h.port, TRUE]; ViewerTools.SetContents[h.memCycle, IO.PutR1[IO.int[test.start]]]; IF h.singleCycle THEN test.proc[NIL, h.cellType, h.port, Eval] ELSE { IF test.start=0 THEN { test.proc[NIL, h.cellType, h.port, Eval]; IF h.cycle=0 THEN { Message["Error: test has zero cycles (maybe you never set clock TRUE?)"]; RETURN[]; }; IF h.firstFreeCycle+h.cycle > LAST[Cycle] THEN { Message["Out of vector memory space"]; RETURN[]; }; BufferToIMS[h: h, cycles: h.cycle, start: h.firstFreeCycle]; test.start _ h.firstFreeCycle; test.length _ h.cycle; h.firstFreeCycle _ h.firstFreeCycle+h.cycle+1; --reserve one word for halt inst. }; IF h.loopTest THEN Jump[h, test.start+test.length, test.start] ELSE Halt[h, test.start+test.length]; Dispatch[h, test.start]; <> IF NOT h.loopTest THEN { count _ IMSTester.ErrorCount[]; IO.PutF[h.outStream, IF count#0 THEN "Fail " ELSE "Pass; "]; IF count#0 THEN IO.PutF[h.outStream, "%g errors; ", IO.card[count]]; }; }; }; }; test: Test _ NARROW[SymTab.Fetch[x: h.testProcsTable, key: h.currentTestProc].val]; IF h.inStream # NIL THEN DO IF NextRun[h] THEN EXIT; DO IF NextWafer[h] THEN EXIT; DO IF NextDie[h ! AbortDieSignal => CONTINUE; AbortWaferSignal => EXIT] THEN EXIT ENDLOOP; ENDLOOP; ENDLOOP; IO.PutF[h.outStream, "(Start: %g, Stop: %g) Done\n", IO.int[test.start], IO.int[test.start+test.length-1]]; IF NOT h.loopTest THEN h.testInProgress _ FALSE; }; Jump: PROC [h: Handle, source: Cycle, dest: Cycle] ~ { tempCycleData: IMSTester.CycleData _ h.buffer[0]; h.buffer[0] _ h.nullCycleData; BufferToIMS[h: h, cycles: 1, start: source, jumps: LIST[[source, dest]]]; h.buffer[0] _ tempCycleData; }; Halt: PROC [h: Handle, cycle: Cycle] ~ { tempCycleData: IMSTester.CycleData _ h.buffer[0]; h.buffer[0] _ h.nullCycleData; BufferToIMS[h: h, cycles: 1, start: cycle, halt: cycle]; h.buffer[0] _ tempCycleData; }; Dispatch: PROC [h: Handle, start: Cycle] ~ { Jump[h, 0, start]; IMSTester.Start[]; }; BufferToIMS: PROC [h: Handle, cycles, start, halt: Cycle_LAST[Cycle], jumps: Jumps_NIL] = { IMSTester.SetIMSMemory[h.forceGroups, h.acquireGroups, h.buffer, cycles, start, halt, jumps]; CheckStop[h]; }; NewBuffer: PROC [h: Handle] = { oldBuffer: IMSTester.Buffer _ h.buffer; h.buffer _ NEW[IMSTester.BufferRec[SELECT TRUE FROM h.cycle<10 => 10, h.cycle<100 => 100, h.cycle<1000 => 1000, h.cycle<10000 => 10000, ENDCASE => 16383]]; FOR i: NAT IN [0..h.buffer.cycle) DO h.buffer[i] _ IF i < h.cycle THEN oldBuffer[i] ELSE NEW[IMSTester.CycleDataRec]; ENDLOOP; }; StartTest: Buttons.ButtonProc = { < {Message["Illegal parameter"]; CONTINUE};>> h: Handle _ NARROW[clientData]; selectedButton: Viewer _ NARROW[parent]; IF h.testInProgress THEN Message["Test in progress"]; IF h.currentTestProc=NIL THEN Message["Please select a test procedure"]; IF NOT h.testInProgress AND h.currentTestProc#NIL THEN { IF h.loopTest THEN Buttons.SetDisplayStyle[selectedButton, $BlackOnGrey]; h.stop _ dont; IF h.inStream # NIL THEN IO.Close[h.inStream]; --just in case last test was aborted Init[h]; DoTest[h ! InterruptSignal => CONTINUE]; Cleanup[h]; }; }; AbortDie: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; IMSTester.Abort[]; h.stop _ abortDie; }; AbortWafer: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; IMSTester.Abort[]; h.stop _ abortWafer; }; AbortTest: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; IMSTester.Abort[]; h.stop _ interrupt; h.testInProgress _ FALSE; }; CheckStop: PROC [h: Handle] = { SELECT h.stop FROM dont => NULL; abortDie => {Message["Abort die"]; ERROR AbortDieSignal}; abortWafer => {Message["Abort wafer"]; ERROR AbortWaferSignal}; interrupt => {Message["Interrupt"]; ERROR InterruptSignal}; ENDCASE => ERROR; }; EnableTester: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; selectedButton: Viewer _ NARROW[parent]; h.enableTester _ NOT h.enableTester; Buttons.SetDisplayStyle[selectedButton, IF h.enableTester THEN $WhiteOnBlack ELSE $BlackOnWhite]; }; EnableStepper: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; selectedButton: Viewer _ NARROW[parent]; h.enableStepper _ NOT h.enableStepper; Buttons.SetDisplayStyle[selectedButton, IF h.enableStepper THEN $WhiteOnBlack ELSE $BlackOnWhite]; }; GetParameters: Buttons.ButtonProc = { ENABLE IO.Error, RuntimeError.BoundsFault => {Message["Illegal parameter"]; CONTINUE}; h: Handle _ NARROW[clientData]; ReallyGetParameters[h]; }; ReallyGetParameters: PROC [h: Handle] = { targetGroup: ROPE _ ViewerTools.GetContents[h.group]; fg: IMSTester.ForceGroup _ NIL; ag: IMSTester.AcquireGroup _ NIL; FOR l: LIST OF ForceSubGroupsRec _ h.forceSubGroups, l.rest WHILE l#NIL DO IF Rope.Equal[l.first.fullName, targetGroup] THEN { fg _ l.first.subGroups.first; ViewerTools.SetContents[h.delay, IO.PutR1[IO.int[fg.delay]]]; ViewerTools.SetContents[h.width, IO.PutR1[IO.int[fg.width]]]; ViewerTools.SetContents[h.hiDrive, IF fg.programable THEN IO.PutR1[IO.real[fg.hiDrive]] ELSE "TTL"]; ViewerTools.SetContents[h.loDrive, IF fg.programable THEN IO.PutR1[IO.real[fg.loDrive]] ELSE "TTL"]; EXIT; }; REPEAT FINISHED => { ViewerTools.SetContents[h.delay, "?"]; ViewerTools.SetContents[h.width, "?"]; ViewerTools.SetContents[h.hiDrive, "?"]; ViewerTools.SetContents[h.loDrive, "?"]; }; ENDLOOP; FOR l: LIST OF AcquireSubGroupsRec _ h.acquireSubGroups, l.rest WHILE l#NIL DO IF Rope.Equal[l.first.fullName, targetGroup] THEN { ag _ l.first.subGroups.first; ViewerTools.SetContents[h.sample, IO.PutR1[IO.int[ag.sample]]]; ViewerTools.SetContents[h.threshold, IF ag.programable THEN IO.PutR1[IO.real[ag.threshold]] ELSE "TTL"]; EXIT; }; REPEAT FINISHED => { ViewerTools.SetContents[h.sample, "?"]; ViewerTools.SetContents[h.threshold, "?"]; }; ENDLOOP; IF fg=NIL AND ag=NIL THEN Message[IO.PutFR1["Group name \"%g\" not found.\n", IO.rope[targetGroup]]]; }; SetParameters: Buttons.ButtonProc = { ENABLE IO.Error, RuntimeError.BoundsFault => {Message["Illegal parameter"]; CONTINUE}; ReallySetParameters: PROC [h: Handle] = { delay: Delay _ 0; width: Width _ 20; sample: Sample _ 0; hiDrive: REAL _ 2.4; loDrive: REAL _ 0.4; threshold: REAL _ 1.4; targetGroup: ROPE _ ViewerTools.GetContents[h.group]; FOR l: LIST OF ForceSubGroupsRec _ h.forceSubGroups, l.rest WHILE l#NIL DO IF Rope.Equal[l.first.fullName, targetGroup] THEN { delay _ IO.GetInt[IO.RIS[ViewerTools.GetContents[h.delay]]]; width _ ((IO.GetInt[IO.RIS[ViewerTools.GetContents[h.width]]]+5)/10)*10; IF l.first.subGroups.first.programable THEN { hiDrive _ IO.GetReal[IO.RIS[ViewerTools.GetContents[h.hiDrive]]]; loDrive _ IO.GetReal[IO.RIS[ViewerTools.GetContents[h.loDrive]]]; }; }; ENDLOOP; FOR l: LIST OF AcquireSubGroupsRec _ h.acquireSubGroups, l.rest WHILE l#NIL DO IF Rope.Equal[l.first.fullName, targetGroup] THEN { sample _ IO.GetInt[IO.RIS[ViewerTools.GetContents[h.sample]]]; IF l.first.subGroups.first.programable THEN threshold _ IO.GetReal[IO.RIS[ViewerTools.GetContents[h.threshold]]]; }; ENDLOOP; <<>> DoSetParameters[h, targetGroup, delay, width, sample, hiDrive, loDrive, threshold]; }; h: Handle _ NARROW[clientData]; ReallySetParameters[h]; }; DoSetParameters: PROC [h: Handle, targetGroup: ROPE, delay: Delay, width: Width, sample: Sample, hiDrive, loDrive, threshold: REAL] = { fg: IMSTester.ForceGroups _ NIL; ag: IMSTester.AcquireGroups _ NIL; FOR l: LIST OF ForceSubGroupsRec _ h.forceSubGroups, l.rest WHILE l#NIL DO IF Rope.Equal[l.first.fullName, targetGroup] THEN { fg _ l.first.subGroups; FOR f: IMSTester.ForceGroups _ fg, f.rest WHILE f#NIL DO f.first.delay _ delay; f.first.width _ ((width+5)/10)*10; IF f.first.programable THEN { f.first.hiDrive _ hiDrive; f.first.loDrive _ loDrive; }; ENDLOOP; }; ENDLOOP; FOR l: LIST OF AcquireSubGroupsRec _ h.acquireSubGroups, l.rest WHILE l#NIL DO IF Rope.Equal[l.first.fullName, targetGroup] THEN { ag _ l.first.subGroups; FOR a: IMSTester.AcquireGroups _ ag, a.rest WHILE a#NIL DO a.first.sample _ sample; IF a.first.programable THEN a.first.threshold _ threshold; ENDLOOP; }; ENDLOOP; ViewerTools.SetContents[h.group, targetGroup]; ReallyGetParameters[h]; IF fg#NIL OR ag#NIL THEN IMSTester.RedefineGroups[fg, ag] ELSE Message[IO.PutFR1["Group name \"%g\" not found.\n", IO.rope[targetGroup]]]; }; Interrupt: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; h.stop _ interrupt; }; Continue: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; IF h.testInProgress AND (h.stop = interrupt) THEN { DoTest[h ! InterruptSignal => CONTINUE]; Cleanup[h]; }; }; SingleCycle: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; selectedButton: Viewer _ NARROW[parent]; h.singleCycle _ NOT h.singleCycle; Buttons.SetDisplayStyle[selectedButton, IF h.singleCycle THEN $WhiteOnBlack ELSE $BlackOnWhite]; }; LoopTest: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; selectedButton: Viewer _ NARROW[parent]; h.loopTest _ NOT h.loopTest; Buttons.SetDisplayStyle[selectedButton, IF h.loopTest THEN $WhiteOnBlack ELSE $BlackOnWhite]; }; StopLoop: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; IF h.testInProgress AND h.loopTest THEN Buttons.SetDisplayStyle[h.startTest, $BlackOnWhite]; IMSTester.Stop[]; h.testInProgress _ FALSE; }; GetErrors: Buttons.ButtonProc = { ENABLE IO.Error, Convert.Error, RuntimeError.BoundsFault => {Message["Illegal ""Mem Cycle"" parameter"]; CONTINUE}; ReallyGetErrors: PROC [h: Handle] = { errors: IMSTester.Errors; test: Test _ NARROW[SymTab.Fetch[x: h.testProcsTable, key: h.currentTestProc].val]; start: Cycle _ Convert.IntFromRope[ViewerTools.GetContents[h.memCycle]]; valid: BOOL _ FALSE; errorCycle: Cycle; IF starttest.start+test.length-1 THEN start _ test.start+test.length-1; SELECT mouseButton FROM red => { [valid, errorCycle] _ IMSTester.GetRawErrors[h.outStream, h.forceGroups, h.acquireGroups, test.start+test.length-1, start, test.start-1]; }; yellow => ViewerTools.SetContents[h.memCycle, IO.PutR1[IO.int[start-1]]]; blue => { errors _ IMSTester.GetErrors[h.acquireGroups, h.buffer, test.start, test.start+test.length-1, start, test.start-1]; FOR l: IMSTester.Errors _ errors, l.rest WHILE l#NIL DO IO.PutF[h.outStream, "Cycle: %g, %g, Expected: %g\n", IO.int[l.first.cycle], IO.rope[GetName[h, l.first.pin.signalName].acquireName], IO.bool[l.first.expected]]; ENDLOOP; IF errors#NIL THEN { valid _ TRUE; errorCycle _ errors.first.cycle; }; }; ENDCASE => ERROR; IF valid THEN ViewerTools.SetContents[h.memCycle, IO.PutR1[IO.int[errorCycle+1]]]; }; h: Handle _ NARROW[clientData]; ReallyGetErrors[h]; }; GetMemory: Buttons.ButtonProc = { ENABLE IO.Error, Convert.Error, RuntimeError.BoundsFault => {Message["Illegal ""Mem Cycle"" parameter"]; CONTINUE}; ReallyGetMemory: PROC [h: Handle] = { test: Test _ NARROW[SymTab.Fetch[x: h.testProcsTable, key: h.currentTestProc].val]; cycle: Cycle _ Convert.IntFromRope[ViewerTools.GetContents[h.memCycle]]; IF mouseButton#yellow THEN { IF cycletest.start+test.length-1 THEN cycle _ test.start+test.length-1; }; IF h.enableTester THEN IMSTester.GetMemory[h.outStream, cycle, h.forceGroups, h.acquireGroups, test.start-1]; cycle _ cycle+(IF mouseButton#blue THEN incr ELSE -incr); ViewerTools.SetContents[h.memCycle, IO.PutR1[IO.int[cycle]]]; }; h: Handle _ NARROW[clientData]; incr: INT _ SELECT TRUE FROM control AND shift=> 8, control=> 4, shift =>2, ENDCASE=>1; ReallyGetMemory[h]; }; DumpErrors: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; test: Test _ NARROW[SymTab.Fetch[x: h.testProcsTable, key: h.currentTestProc].val]; valid: BOOL; errorCycle: Cycle; s: IO.STREAM _ FS.StreamOpen[fileName: Rope.Cat[h.currentTestProc, ".err"], accessOptions: $create, wDir: h.wDir]; errorCycle _ test.start; DO [valid, errorCycle] _ IMSTester.GetRawErrors[s, h.forceGroups, h.acquireGroups, test.start+test.length-1, errorCycle, test.start-1]; IF NOT valid THEN EXIT; errorCycle _ errorCycle+1; ENDLOOP; IO.Close[s]; }; DumpMemory: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; test: Test _ NARROW[SymTab.Fetch[x: h.testProcsTable, key: h.currentTestProc].val]; s: IO.STREAM _ FS.StreamOpen[fileName: Rope.Cat[h.currentTestProc, ".mem"], accessOptions: $create, wDir: h.wDir]; FOR cycle: Cycle IN [test.start..test.start+test.length) DO IMSTester.GetMemory[s, cycle, h.forceGroups, h.acquireGroups, test.start-1]; ENDLOOP; IO.Close[s]; }; Message: PROC [rope: ROPE] = { MessageWindow.Append[rope, TRUE]; MessageWindow.Blink[]; MessageWindow.Append[rope, TRUE]; }; ForceDataToBuffer: PROC [h: Handle] = { cycle: Cycle _ h.cycle; FOR l: LIST OF MapRec _ h.forceMap, l.rest WHILE l#NIL DO board: IMSTester.Board _ l.first.b; pod: IMSTester.PodChannel _ l.first.p; port: Ports.Port _ l.first.port; index: NAT _ l.first.index; inhibit: BOOL _ (IF port.driveType=aggregate THEN port.d ELSE port.ds[index]) IN [FIRST[Ports.Drive]..none]; SELECT port.levelType FROM l, ls => { SELECT (IF port.levelType=l THEN port.l ELSE port.ls[index]) FROM L => { h.buffer[cycle][board][pod].forceData _ FALSE; h.buffer[cycle][board][pod].inhibit _ FALSE; }; H => { h.buffer[cycle][board][pod].forceData _ TRUE; h.buffer[cycle][board][pod].inhibit _ FALSE; }; X => h.buffer[cycle][board][pod].inhibit _ TRUE; ENDCASE => ERROR; }; b, bs => { h.buffer[cycle][board][pod].forceData _ IF port.levelType=b THEN port.b ELSE port.bs[index]; h.buffer[cycle][board][pod].inhibit _ inhibit; }; c => { bitMask: CARDINAL _ Basics.BITSHIFT[08000h, -port.fieldStart-index]; h.buffer[cycle][board][pod].forceData _ Basics.BITAND[port.c, bitMask]#0; h.buffer[cycle][board][pod].inhibit _ inhibit; }; lc => { bitMask: LONG CARDINAL _ Basics.DoubleShift[[lc[080000000h]], -port.fieldStart-index].lc; h.buffer[cycle][board][pod].forceData _ Basics.DoubleAnd[[lc[port.lc]], [lc[bitMask]]].lc#0; h.buffer[cycle][board][pod].inhibit _ inhibit; }; ENDCASE => ERROR; CheckStop[h]; ENDLOOP; }; CompareDataToBuffer: PROC [h: Handle] = { cycle: Cycle _ h.cycle; FOR l: LIST OF MapRec _ h.acquireMap, l.rest WHILE l#NIL DO board: IMSTester.Board _ l.first.b; pod: IMSTester.PodChannel _ l.first.p; port: Ports.Port _ l.first.port; index: NAT _ l.first.index; mask: BOOL _ (IF port.driveType=aggregate THEN port.d ELSE port.ds[index]) # expect; SELECT port.levelType FROM l, ls => { SELECT (IF port.levelType=l THEN port.l ELSE port.ls[index]) FROM L => { h.buffer[cycle][board][pod].compareData _ FALSE; h.buffer[cycle][board][pod].mask _ mask }; H => { h.buffer[cycle][board][pod].compareData _ TRUE; h.buffer[cycle][board][pod].mask _ mask }; X => h.buffer[cycle][board][pod].mask _ mask; ENDCASE => ERROR; }; b, bs => { h.buffer[cycle][board][pod].compareData_IF port.levelType=b THEN port.b ELSE port.bs[index]; h.buffer[cycle][board][pod].mask _ mask; }; c => { bitMask: CARDINAL _ Basics.BITSHIFT[08000h, -port.fieldStart-index]; h.buffer[cycle][board][pod].compareData _ Basics.BITAND[port.c, bitMask]#0; h.buffer[cycle][board][pod].mask _ mask; }; lc => { bitMask: LONG CARDINAL _ Basics.DoubleShift[[lc[080000000h]], -port.fieldStart-index].lc; h.buffer[cycle][board][pod].compareData _ Basics.DoubleAnd[[lc[port.lc]], [lc[bitMask]]].lc#0; h.buffer[cycle][board][pod].mask _ mask; }; ENDCASE => ERROR; CheckStop[h]; ENDLOOP; }; MapPortToBuffer: PROC [h: Handle] = { FlushMark: PROC [wire: Core.Wire, foundMark: BOOL] ~ { foundMark _ foundMark OR CoreProperties.GetWireProp[wire, $mark] # NIL; CoreProperties.PutWireProp[wire, $mark, NIL]; IF wire.size=0 AND NOT foundMark THEN h.outStream.PutF["Public with no explicit assignment: %g\n", IO.rope[CoreOps.GetFullWireName[h.cellType.public, wire]] ]; FOR i: INT IN [0..wire.size) DO FlushMark[wire[i], foundMark] ENDLOOP;}; EachPair: PROC [wire: Core.Wire, port: Ports.Port] RETURNS [subElements: BOOL _ TRUE, quit: BOOL _ FALSE] --Ports.EachPortPairProc-- = { podChannel: IMSTester.PodChannel _ (SELECT a.first.pod FROM A=>0, B=>8, AT=>16, BT=>17 ENDCASE=>ERROR) + a.first.channel; IF CoreOps.IsFullWireName[h.cellType.public, wire, a.first.name] AND a.first.group#0 THEN { found _ TRUE; CoreProperties.PutWireProp[wire, $mark, $mark]; IF port#NIL THEN rootPort _ port; IF (g.first.directionality=force) OR (g.first.directionality=biDirectional) THEN { FOR l: LIST OF MapRec _ h.forceMap, l.rest WHILE l#NIL DO IF l.first.b=a.first.board AND l.first.p=podChannel THEN ERROR; --two force ports map to same buffer ENDLOOP; h.forceMap _ CONS[[a.first.board, podChannel, rootPort, IF port=NIL THEN count ELSE 0], h.forceMap]; }; IF (g.first.directionality=acquire) OR (g.first.directionality=biDirectional) THEN { FOR l: LIST OF MapRec _ h.acquireMap, l.rest WHILE l#NIL DO IF l.first.b=a.first.board AND l.first.p=podChannel THEN ERROR; --two acquire ports map to same buffer ENDLOOP; h.acquireMap _ CONS[[a.first.board, podChannel, rootPort, IF port=NIL THEN count ELSE 0], h.acquireMap]; }; RETURN[TRUE]; }; IF port#NIL AND port.levelType#composite THEN {count _ 0; rootPort _ port} ELSE count _ count+1; }; count: NAT _ 0; a: Assignments; g: Groups; badAssignments: BOOL_FALSE; found: BOOL; rootPort: Ports.Port; h.outStream.PutRope["Checking Assignments\n"]; FOR g _ h.groups, g.rest WHILE g#NIL DO FOR a _ h.assignments, a.rest WHILE a#NIL DO IF g.first.number=a.first.group THEN { found _ FALSE; [] _ Ports.VisitBinding[h.cellType.public, h.port, EachPair]; IF NOT found THEN { badAssignments _ TRUE; h.outStream.PutF["Assignment not found in public: %g\n", IO.rope[a.first.name] ] }}; ENDLOOP; ENDLOOP; FlushMark[h.cellType.public, FALSE]; IF badAssignments THEN BadAssignments[]}; BadAssignments: SIGNAL = CODE; LimitNameLength: PROC [nameTab: SymTab.Ref, name: ROPE, length: NAT] RETURNS [newName: ROPE] = { <> IF name = NIL THEN name _ "IMS"; IF Rope.Length[name] > length THEN { c: CHAR; beforeRope, numericRope, afterRope: ROPE _ NIL; beforeLength, numericLength, afterLength: NAT; after: BOOL _ FALSE; s: IO.STREAM _ IO.RIS[name]; WHILE NOT s.EndOf[] DO SELECT (c _ s.GetChar[]) FROM IN ['!..'$], IN ['&..'+], '-, '., '/, ':, '<, '>, '?, IN ['A..'~] => IF after THEN afterRope _ Rope.Concat[afterRope, Rope.FromChar[c]] ELSE beforeRope _ Rope.Concat[beforeRope, Rope.FromChar[c]]; --any printable char but SP, ', '= '% and '; are OK '%, IN ['0..'9] => { numericRope _ Rope.Concat[numericRope, Rope.FromChar[c]]; WHILE NOT s.EndOf[] AND (c _ s.PeekChar[]) >= '0 AND c <='9 DO numericRope _ Rope.Cat[numericRope, Rope.FromChar[s.GetChar[]]]; ENDLOOP; after _ TRUE; }; ENDCASE => ERROR -- illegal character in name ENDLOOP; beforeLength _ Rope.Length[beforeRope]; numericLength _ Rope.Length[numericRope]; afterLength _ Rope.Length[afterRope]; IF numericLength < length THEN IF (beforeLength + numericLength) < length THEN IF (beforeLength + numericLength + afterLength) < length THEN newName _ name ELSE newName _ Rope.Substr[name, 0, length] ELSE newName _ Rope.Concat[Rope.Substr[beforeRope, 0, length-numericLength], numericRope] ELSE newName _ Rope.Substr[numericRope, 0, length]; WHILE NOT SymTab.Insert[nameTab, newName, name] DO --if short name exists, add %## to it number, index: INTEGER; IF (index _ Rope.Find[newName, "%"]) # -1 THEN { number _ (Rope.Fetch[newName, index+1]-'0)*10 + (Rope.Fetch[newName, index+2]-'0)+1; newName _ Rope.Substr[newName, 0, index]; newName _ IO.PutFR["%g%%%02g", IO.rope[newName], IO.card[number]]; } ELSE { newName _ Rope.Substr[newName, 0, length-3]; newName _ Rope.Concat[newName, "%00"]; }; ENDLOOP; } ELSE newName _ name; IF NOT SymTab.Insert[nameTab, name, newName] THEN ERROR; --name multiply defined }; LimitGroupSize: PROC [h: Handle, groups: PodTimingGroups, boardToSlot: REF BoardToSlot] RETURNS [listOfGroups: LIST OF PodTimingGroups] = { <> newGroup, reversedGroup: PodTimingGroups; reversedGroupList: LIST OF PodTimingGroups; channels: NAT; addToGroup: BOOL; channels _ 0; newGroup _ NIL; reversedGroupList _ NIL; FOR p: PodTimingGroups _ groups, p.rest WHILE p#NIL DO FOR l: IMSTester.Pins _ p.first.pins, l.rest WHILE l#NIL DO channels _ channels + 1; ENDLOOP; addToGroup _ channels <= 32 AND (IF newGroup#NIL THEN boardToSlot[newGroup.first.board].programable=boardToSlot[p.first.board].programable ELSE TRUE); IF addToGroup THEN newGroup _ CONS[p.first, newGroup]; IF NOT addToGroup THEN { <> reversedGroup _ NIL; FOR p: PodTimingGroups _ newGroup, p.rest WHILE p#NIL DO reversedGroup _ CONS[p.first, reversedGroup]; ENDLOOP; listOfGroups _ CONS[reversedGroup, listOfGroups]; channels _ 0; newGroup _ LIST[p.first]; FOR l: IMSTester.Pins _ p.first.pins, l.rest WHILE l#NIL DO channels _ channels + 1; ENDLOOP; }; ENDLOOP; <> reversedGroup _ NIL; IF newGroup#NIL THEN FOR p: PodTimingGroups _ newGroup, p.rest WHILE p#NIL DO reversedGroup _ CONS[p.first, reversedGroup]; ENDLOOP; listOfGroups _ CONS[reversedGroup, listOfGroups]; }; MakePodTimingGroup: PROC [h: Handle, g: Group, boardToSlot: REF BoardToSlot, nameTab: SymTab.Ref] RETURNS [podTimingGroups: IMSTester.PodTimingGroups] = { FOR a: Assignments _ h.assignments, a.rest WHILE a#NIL DO IF a.first.group = g.number THEN { FOR l: PodTimingGroups _ podTimingGroups, l.rest WHILE l#NIL DO IF l.first.board = a.first.board AND l.first.podTiming = a.first.pod THEN { FOR p: IMSTester.Pins _ l.first.pins, p.rest WHILE p#NIL DO IF p.first.channel = a.first.channel THEN ERROR; --channel assigned twice ENDLOOP; l.first.pins _ CONS[NEW[IMSTester.PinRec _ [ channel: a.first.channel, signalName: LimitNameLength[nameTab, a.first.name, signalNameLength], packagePin: a.first.probeCardPin]], l.first.pins]; EXIT; }; REPEAT FINISHED => podTimingGroups _ CONS[NEW[IMSTester.PodTimingGroupRec _ [ slot: boardToSlot[a.first.board].slot, board: a.first.board, podTiming: a.first.pod, pins: LIST[NEW[IMSTester.PinRec _ [ channel: a.first.channel, signalName: LimitNameLength[nameTab, a.first.name, signalNameLength], packagePin: a.first.probeCardPin]]]]], podTimingGroups]; ENDLOOP; }; ENDLOOP; }; MakeForceAcquireGroups: PROC [h: Handle] = { listOfGroups: LIST OF PodTimingGroups; count: NAT; forceSubGroup: IMSTester.ForceGroup; acquireSubGroup: IMSTester.AcquireGroup; FOR g: Groups _ h.groups, g.rest WHILE g#NIL DO IF g.first.directionality=force OR g.first.directionality=biDirectional THEN { listOfGroups _ LimitGroupSize[h, MakePodTimingGroup[h, g.first, h.forceBoardToSlot, h.forceNamesTab], h.forceBoardToSlot]; h.forceSubGroups _ CONS[[g.first.name, NIL], h.forceSubGroups]; count _ 0; FOR l: LIST OF PodTimingGroups _ listOfGroups, l.rest WHILE l#NIL DO forceSubGroup _ NEW[IMSTester.ForceGroupRec _ [LimitNameLength[h.forceNamesTab, IO.PutFR["F%g%%%02g", IO.rope[g.first.name], IO.card[count]], groupNameLength], l.first, g.first.format, g.first.delay, g.first.width, g.first.programable, g.first.hiDrive, g.first.loDrive]]; h.forceGroups _ CONS[forceSubGroup, h.forceGroups]; h.forceSubGroups.first.subGroups _ CONS[forceSubGroup, h.forceSubGroups.first.subGroups]; count _ count+1; ENDLOOP; }; IF g.first.directionality=acquire OR g.first.directionality=biDirectional THEN { listOfGroups _ LimitGroupSize[h, MakePodTimingGroup[h, g.first, h.acquireBoardToSlot, h.acquireNamesTab], h.acquireBoardToSlot]; h.acquireSubGroups _ CONS[[g.first.name, NIL], h.acquireSubGroups]; count _ 0; FOR l: LIST OF PodTimingGroups _ listOfGroups, l.rest WHILE l#NIL DO acquireSubGroup _ NEW[IMSTester.AcquireGroupRec _ [LimitNameLength[h.acquireNamesTab, IO.PutFR["A%g%%%02g", IO.rope[g.first.name], IO.card[count]], groupNameLength], l.first, g.first.sample, g.first.compare, g.first.programable, g.first.threshold]]; h.acquireGroups _ CONS[acquireSubGroup, h.acquireGroups]; h.acquireSubGroups.first.subGroups _ CONS[acquireSubGroup, h.acquireSubGroups.first.subGroups]; count _ count+1; ENDLOOP; }; ENDLOOP; }; NotifyPeriodChange: PROC [h: Handle, period: Period] ~ { proc: ICTest.PeriodChangeProc _ NARROW[SymTab.Fetch[x: h.testProcsTable, key: periodChangeProc].val, REF ICTest.PeriodChangeProc]^; IMSTester.SetCyclePeriod[period]; FOR g: Groups _ proc[period], g.rest WHILE g#NIL DO first: Group _ g.first; DoSetParameters[h, first.name, first.delay, first.width, first.sample, first.hiDrive, first.loDrive, first.threshold]; ENDLOOP; }; Init: PROC[h: Handle] = { filename: ROPE; period: Period; filename _ ViewerTools.GetContents[h.waferFile]; h.inStream _ FS.StreamOpen[fileName: filename, wDir: h.wDir ! FS.Error => {Message[IO.PutFR["Wafer file: %g not found", IO.rope[filename]]]; CONTINUE}]; IF h.port=NIL THEN h.port _ Ports.CreatePort[h.cellType, TRUE]; IF h.clockAName#NIL THEN h.clockAPort _ h.port[Ports.PortIndex[h.cellType.public, h.clockAName]]; IF h.clockBName#NIL THEN h.clockBPort _ h.port[Ports.PortIndex[h.cellType.public, h.clockBName]]; <> IMSTester.checkSyntax _ NOT h.enableTester; period _ ((IO.GetInt[IO.RIS[ViewerTools.GetContents[h.period]]]+5)/10)*10; ViewerTools.SetContents[h.period, IO.PutR1[IO.int[period]]]; IF h.forceNamesTab=NIL THEN FirstStart[h, period]; --first time Start Test is pressed IF h.lastPeriod#period THEN NotifyPeriodChange[h, period]; h.lastPeriod _ period; h.cycle _ 0; <> }; FirstStart: PROC [h: Handle, period: Period] ~ { forceBoard, acquireBoard, programable: PACKED ARRAY IMSTester.SlotNumber OF BOOLEAN; board: NAT; h.forceNamesTab _ SymTab.Create[]; h.acquireNamesTab _ SymTab.Create[]; [forceBoard, acquireBoard, programable] _ IMSTester.Initialize[h.wDir]; board _ 0; FOR slot: IMSTester.SlotNumber IN IMSTester.SlotNumber DO IF forceBoard[slot] THEN { h.forceBoardToSlot[board] _ [slot, programable[slot]]; board _ board+1; }; ENDLOOP; board _ 0; FOR slot: IMSTester.SlotNumber IN IMSTester.SlotNumber DO IF acquireBoard[slot] THEN { h.acquireBoardToSlot[board] _ [slot, programable[slot]]; board _ board+1; }; ENDLOOP; MakeForceAcquireGroups[h]; MapPortToBuffer[h]; IMSTester.SetCyclePeriod[period]; --have to do this BEFORE defining groups IMSTester.DefineGroups[h.forceGroups, h.acquireGroups]; h.buffer _ NEW[IMSTester.BufferRec[1]]; h.buffer[0] _ NEW[IMSTester.CycleDataRec]; h.firstFreeCycle _ 1; -- reserve location zero for dispatches and singlecycle execution h.nullCycleData _ NEW[IMSTester.CycleDataRec]; FOR b: Board IN Board DO FOR p: PodChannel IN PodChannel DO h.nullCycleData[b][p].forceData _ FALSE; h.nullCycleData[b][p].inhibit _ TRUE; h.nullCycleData[b][p].compareData _ FALSE; h.nullCycleData[b][p].mask _ TRUE; ENDLOOP; ENDLOOP; }; Cleanup: PROC [h: Handle] = { <> IF NOT h.loopTest THEN IMSTester.Stop[]; }; GetName: PROC [h: Handle, key: Rope.ROPE] RETURNS [forceName, acquireName: Rope.ROPE] = { val: SymTab.Val; found: BOOL; [found, val] _ SymTab.Fetch[h.forceNamesTab, key]; forceName _ IF found THEN NARROW[val, Rope.ROPE] ELSE NIL; [found, val] _ SymTab.Fetch[h.acquireNamesTab, key]; acquireName _ IF found THEN NARROW[val, Rope.ROPE] ELSE NIL; }; LookUpName: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO failed}]; key, forceName, acquireName: Rope.ROPE; FOR i: NAT IN [1..argv.argc) DO key _ argv[i]; IF Rope.Length[key] = 0 THEN LOOP ELSE EXIT; ENDLOOP; [forceName, acquireName] _ GetName[NARROW[cmd.procData.clientData], key]; IF forceName#NIL THEN IO.PutF[cmd.out, "Force name: %g\n", IO.rope[forceName]]; IF acquireName#NIL THEN IO.PutF[cmd.out, "Acquire name: %g\n", IO.rope[forceName]]; IF forceName=NIL AND acquireName=NIL THEN IO.PutF[cmd.out, "%g not found\n", IO.rope[key]]; EXITS failed => NULL; }; END.