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 [ 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, testButtonContainer: Viewer _ NIL, testButtonList: LIST OF Button _ NIL, testProcsTable: SymTab.Ref _ NIL, currentTestProc: ROPE _ NIL, 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]]; 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; h.testButtonContainer _ Containers.Create[[wy: height, wh: entryVSpace, scrollable: FALSE, parent: viewer, border: FALSE]]; Containers.ChildXBound[viewer, h.testButtonContainer]; height _ height + entryVSpace; 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 h.clockAPort.b) OR (h.clockBPort#NIL AND h.clockBPort.b) 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 = { 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.d=force OR port.d=drive THEN FALSE ELSE TRUE; 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.d=expect THEN FALSE ELSE TRUE; 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 _ TRUE }; H => { h.buffer[cycle][board][pod].compareData _ TRUE; h.buffer[cycle][board][pod].mask _ TRUE }; X => h.buffer[cycle][board][pod].mask _ TRUE; 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. φICTestImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Created by: Gasbarro December 3, 1985 6:15:34 pm PST Last Edited by: Gasbarro February 12, 1987 9:06:04 am PST Last Edited by: Don Curry July 11, 1987 6:02:17 pm PDT Jean-Marc Frailong February 3, 1988 12:45:57 pm PST Barth, September 10, 1987 3:42:59 pm PDT -- Standard button state -- -- Test buttons state-- -- Typescript -- ***Standard Buttons*** Button["Interrupt", col3, Interrupt, FALSE]; Button["Continue", col3, Continue]; ***Test Buttons*** ***TypeScript*** EGlas.LampOn[]; IF h.testInProgress THEN EGlas.Load[]; --don't load wafer first time EGlas.Seek[h.currentDie.x, h.currentDie.y]; EGlas.ZUp[]; EGlas.LampOff[]; IF h.enableStepper THEN EGlas.LampOn[]; ENABLE IO.Error, RuntimeError.BoundsFault => {Message["Illegal parameter"]; CONTINUE}; Looks for ropes in the form: "beforeRope, numericRope, afterRope". Truncates afterRope first and numericRope last in order to get rope to conform to length. Splits up groups which are larger that the IMS maximum of 32 channels into subgroups. Also splits up groups which span programable drive level or acquire threshold modules so that such modules are referenced by unique group names (another IMS restriction). re-reverse the elements on the list (for aesthetic reasons only) add the leftovers to the list (in aesthetic order) IF h.clockAPort=NIL AND h.clockBPort=NIL THEN ERROR; --can't find clocks IF h.enableStepper THEN EGlas.Init[]; IF h.enableStepper THEN EGlas.LampOn[]; Κ0Z˜šœ™Icodešœ Οmœ1™Jšœžœ "˜Kšžœžœžœ ˜3—KšžœL˜Nšžœžœ˜Kšœ™Kšžœžœ ™DKšœ˜—Kšœ˜—K˜—Kšœ˜K˜—š ‘œžœ žœžœžœ˜=š‘œ˜#K˜ šžœžœžœžœžœžœžœžœžœžœžœ˜„Kšœ˜Kšœ˜šžœžœ˜Kšœ0˜0Kšœ˜Kšœžœ˜Kšœ˜Kšžœžœ˜.K˜—K˜—K˜K˜—Kšœžœžœ˜Kšœžœ˜Kšœžœžœ˜ šžœžœ˜šžœžœž˜Kšœžœžœžœ˜=š žœžœžœžœžœ žœž˜1Kšœžœ˜(Kšœžœ˜(šœžœ˜2Kšžœžœžœ˜,—Kšžœ žœ˜Kšžœ:žœ˜G—Kšžœ˜—šžœžœžœ˜Jšœžœ ˜Kšœžœžœžœ˜bKšžœ!žœžœ˜SK˜—K˜—K˜šžœžœžœ˜K˜Jšœžœ˜šžœžœ˜Kšœ+™+Kšœ ™ Kšœ™K˜—Kšœ$žœ˜*Kšœ-žœ˜Bšžœžœ žœžœ˜Ešžœ žœ˜Kšœ žœ˜)šžœ žœ˜K˜IKšžœ˜ K˜—šžœžœžœ˜0K˜&Kšžœ˜ K˜—Kšœ<˜Kš žœ%žœ žœ žœžœ(˜qK˜—Kšžœ˜—K™KšœS˜SKšœ˜K˜—Kšœ žœ ˜Kšœ˜K˜K˜—š‘œžœžœKžœ˜‡Kšœžœ˜ Kšœžœ˜"š žœžœžœ.žœžœž˜Jšžœ+žœ˜3Kšœ˜šžœ'žœžœž˜8Kšœ˜Kšœ"˜"šžœžœ˜Kšœ˜Kšœ˜K˜—Kšžœ˜—K˜—Kšžœ˜—š žœžœžœ2žœžœž˜Nšžœ+žœ˜3Kšœ˜šžœ)žœžœž˜:Kšœ˜Kšžœžœ˜:Kšžœ˜—K˜—Kšžœ˜—Kšœ.˜.Kšœ˜š žœžœžœžœžœ!˜9Kšžœ žœ*žœ˜P—Kšœ˜K˜—š‘ œ˜!Kšœ žœ ˜Kšœ˜Kšœ˜K˜—š‘œ˜ Kšœ žœ ˜šžœžœžœ˜3Kšœžœ˜(Kšœ ˜ K˜—Kšœ˜K˜—š‘ œ˜#Kšœ žœ ˜Kšœžœ ˜(Kšœžœ˜"Kšœ(žœžœžœ˜`Kšœ˜K˜—š‘œ˜ Kšœ žœ ˜Kšœžœ ˜(Kšœ žœ ˜Kšœ(žœ žœžœ˜]Kšœ˜K˜—š‘œ˜ Kšœ žœ ˜Kšžœžœ žœ5˜\Kšœ˜Kšœžœ˜Kšœ˜K˜—š‘ œ˜!Kšžœžœ`žœ˜sš‘œžœ˜%Kšœ˜Kšœ žœ@˜SKšœH˜HKšœžœžœ˜'Kšžœžœ˜,Kšžœ žœ"˜Hšžœ ž˜šœ˜Kšœ‰˜‰Kšœ˜—Kšœ.žœžœ˜Išœ ˜ Kšœs˜sšžœ&žœžœž˜7Kšžœ4žœžœ7žœ˜‘Kšžœ˜—šžœžœžœ˜Kšœžœ˜ Kšœ ˜ K˜—Kšœ˜—Kšžœžœ˜—Kšžœžœ%žœžœ˜RK˜K˜—Kšœ žœ ˜Kšœ˜Kšœ˜K˜—š‘ œ˜!Kšžœžœ`žœ˜sš‘œžœ˜%Kšœ žœ@˜SKšœH˜Hšžœžœ˜Kšžœžœ˜,Kšžœ žœ"˜HK˜—KšžœžœW˜mKšœžœžœžœ˜9Kšœ$žœžœ˜=K˜K˜—Kšœ žœ ˜Kš œžœžœžœžœ žœ$žœ˜WKšœ˜Kšœ˜K˜—š‘ œ˜"Kšœ žœ ˜Kšœ žœ@˜SKšœžœ˜ Kšœžœžœžœa˜rKšœ˜šž˜Kšœ„˜„Kšžœžœžœžœ˜Kšœ˜Kšžœ˜—Kšžœ ˜ Kšœ˜K˜—š‘ œ˜"Kšœ žœ ˜Kšœ žœ@˜SKšœžœžœžœa˜ršžœžœ&ž˜;KšœL˜LKšžœ˜—Kšžœ ˜ Kšœ˜K˜—š‘œžœžœ˜Kšœžœ˜!Kšœ˜Kšœžœ˜!Kšœ˜K˜—š‘œžœ˜'Kšœ˜š žœžœžœžœžœž˜9Kšœ#˜#Kšœ&˜&Kšœ ˜ Kšœžœ˜Kšœ žœžœžœžœžœžœžœ˜Ešžœž˜šœ ˜ š žœžœžœžœž˜Ašœ˜Kšœ(žœ˜.Kšœ&žœ˜,Kšœ˜—šœ˜Kšœ(žœ˜-Kšœ&žœ˜,Kšœ˜—Kšœ+žœ˜0Kšžœžœ˜—K˜—šœ ˜ Kšœ(žœžœžœ˜\Kšœ.˜.Kšœ˜—šœ˜Kšœ žœ žœ!˜DKšœ/žœ˜IKšœ.˜.Kšœ˜—šœ˜Kšœ žœžœC˜YKšœ\˜\Kšœ.˜.K˜—Kšžœžœ˜—K˜ Kšžœ˜—K˜K˜—š‘œžœ˜)Kšœ˜š žœžœžœžœžœž˜;Kšœ#˜#Kšœ&˜&Kšœ ˜ Kšœžœ˜Kš œžœžœžœžœžœžœ˜3šžœž˜šœ ˜ š žœžœžœžœž˜Ašœ˜Kšœ*žœ˜0Kšœ#ž˜'Kšœ˜—šœ˜Kšœ*žœ˜/Kšœ#ž˜'Kšœ˜—Kšœ(žœ˜-Kšžœžœ˜—K˜—šœ ˜ Kšœ(žœžœžœ˜\Kšœ(˜(Kšœ˜—šœ˜Kšœ žœ žœ!˜DKšœ1žœ˜KKšœ(˜(Kšœ˜—šœ˜Kšœ žœžœC˜YKšœ^˜^Kšœ(˜(K˜—Kšžœžœ˜—K˜ Kšžœ˜—K˜K˜—š‘œžœ˜%š‘ œžœžœ˜6Kšœžœ+žœ˜GKšœ-˜-šžœ žœžœ ˜ šžœ=˜AKšžœ:˜<——Kš žœžœžœžœžœ˜H—š‘œžœ%žœžœžœžœžœ œ˜ˆKš œ$žœ žœ žœžœžœžœ˜yšžœ?žœžœ˜[Kšœžœ˜ Kšœ/˜/Kšžœžœžœ˜!šžœ žœ(žœ˜Rš žœžœžœžœžœž˜9Kš žœžœžœžœ $˜dKšžœ˜—Kš œ žœ'žœžœžœžœ˜dK˜—šžœ"žœ(žœ˜Tš žœžœžœžœžœž˜;Kš žœžœžœžœ &˜fKšžœ˜—Kš œžœ'žœžœžœžœ˜hK˜—Kšžœžœ˜ K˜—šžœžœžœžœ˜JKšžœ˜—K˜—K˜Kšœžœ˜Kšœ˜Kšœ ˜ Kšœž ˜Kšœž˜ K˜Kšœ.˜.šžœžœžœž˜'šžœžœžœž˜,šžœžœ˜&Kšœžœ˜Kšœ=˜=šžœžœžœ˜Kšœžœ˜KšœT˜T——Kšžœ˜—Kšžœ˜—Kšœžœ˜$Kšžœžœ˜)—K˜š‘œžœžœ˜K˜—š ‘œžœžœ žœžœ žœ˜`Jšœ™Jšžœžœžœ˜ šžœžœ˜$Jšœžœ˜Jšœ$žœžœ˜/Jšœ*žœ˜.Jšœžœžœ˜Jš œžœžœžœžœ˜šžœžœ ž˜šžœž˜Jš žœ žœ'žœ žœžœ6žœ9 3˜ψšœžœ˜Jšœ9˜9š žœžœ žœžœžœ˜?Jšœ@˜@Jšžœ˜—Jšœžœ˜ J˜—Jšžœžœ ˜-—Jšžœ˜—Jšœ'˜'Jšœ)˜)Jšœ%˜%šžœžœ˜šžœ)žœ˜0šžœ7žœ˜LJšžœ'˜+—JšžœU˜Y—Jšžœ/˜3—šžœžœ'ž &˜XJšœžœ˜šžœ(žœ˜0J˜TJšœ)˜)Jšœ žœžœžœ˜BJšœžœ˜Jšœ,˜,Jšœ&˜&J˜—Jšžœ˜—Kšœžœ˜—Kš žœžœ'žœžœ ˜PK˜K˜—š ‘œžœ3žœžœžœžœ˜‹Kšœƒ™ƒKšœ)˜)Kšœžœžœ˜+Kšœ žœ˜Kšœ žœ˜Kšœ ˜ Kšœ žœ˜Kšœžœ˜šžœ%žœžœž˜6šžœ*žœžœž˜;Kšœ˜Kšžœ˜—šœžœ˜ šœžœ žœž˜KšœT˜TKšžœžœ˜ ——Kšžœ žœ žœ˜6šžœžœ žœ˜Kšœ@™@Kšœžœ˜šžœ'žœžœž˜8Kšœžœ˜-Kšžœ˜—Kšœžœ˜1Kšœ ˜ Kšœ žœ ˜šžœ*žœžœž˜;Kšœ˜Kšžœ˜—K˜—Kšžœ˜—Kšœ2™2Kšœžœ˜š žœ žœžœžœ'žœžœž˜MKšœžœ˜-Kšžœ˜—Kšœžœ˜1K˜K˜—š‘œžœ$žœ#žœ1˜ššžœ(žœžœž˜9šžœžœ˜"šžœ.žœžœž˜?šžœžœ!žœ˜Kšžœ*žœžœž˜;Kšžœ#žœžœ ˜IKšžœ˜—šœžœžœ˜,Kšœ˜KšœF˜FKšœ2˜2—Kšžœ˜K˜—šž˜šžœ˜ šœžœžœ ˜:Kšœ&˜&Kšœ˜Kšœ˜šœžœžœ˜#Kšœ˜KšœE˜EKšœ8˜8————Kšžœ˜ —K˜—Kšžœ˜—˜K˜——š‘œžœ˜,Kšœžœžœ˜&Kšœžœ˜ Kšœ$˜$Kšœ(˜(šžœžœžœž˜/šžœžœ&žœ˜NKšœz˜zKšœžœžœ˜?Kšœ ˜ š žœžœžœ(žœžœž˜DKš œžœ=žœžœžœ˜Kšœžœ˜3Kšœ#žœ2˜YKšœ˜Kšžœ˜—K˜—šžœ žœ&žœ˜PKšœ€˜€Kšœžœžœ˜CKšœ ˜ š žœžœžœ(žœžœž˜DKš œžœAžœžœžœt˜ωKšœžœ#˜9Kšœ%žœ6˜_Kšœ˜Kšžœ˜—K˜—Kšžœ˜—K˜K˜—š‘œžœ ˜8Kšœ žœ?žœ˜ƒKšœ!˜!šžœ"žœžœž˜3Kšœ˜Kšœv˜vKšžœ˜—K˜K˜—š‘œžœ˜Kšœ ž˜K˜K˜Kšœ0˜0šœ žœ/žœ ˜IKšœ žœ#žœžœ˜N—Kšžœžœžœ'žœ˜?JšžœžœžœI˜aJšžœžœžœI˜aJš žœžœžœžœžœžœ ™HKšœžœ˜+Kšœ žœžœžœ/˜JKšœ"žœžœ˜