<> <> <> <> DIRECTORY Basics, Buttons, ChoiceButtons, Containers, Core, CoreOps, CoreProperties, EGlas, FS, ICTestNew, IO, IMSTester, List, MessageWindow, Ports, RefTab, Rope, --Rosemary,-- Rules, ViewerClasses, ViewerIO, ViewerOps, ViewerTools; ICTestNewImpl: CEDAR PROGRAM IMPORTS Basics, Buttons, ChoiceButtons, Containers, CoreOps, CoreProperties, EGlas, FS, IO, IMSTester, List, MessageWindow, Ports, RefTab, Rope, --Rosemary,-- Rules, ViewerIO, ViewerOps, ViewerTools EXPORTS ICTestNew = BEGIN ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; NSec: TYPE = IMSTester.NSec; FormatType: TYPE = IMSTester.FormatType; PodTimingGroups: TYPE = IMSTester.PodTimingGroups; Board: TYPE = IMSTester.Board; PodTiming: TYPE = IMSTester.PodTiming; Channel: TYPE = IMSTester.Channel; PodChannel: TYPE = IMSTester.PodChannel; AbortDieSignal: PUBLIC ERROR = CODE; AbortWaferSignal: PUBLIC ERROR = CODE; InterruptSignal: PUBLIC ERROR = CODE; Stop: TYPE = {dont, abortDie, abortWafer, interrupt}; DiePosition: TYPE = RECORD [x,y: NAT]; TestHandle: TYPE = REF TestHandleRec; TestHandleRec: TYPE = RECORD[h: Handle, proc: ICTestNew.TestProc]; Handle: TYPE = REF ICTestRec; ICTestRec: PUBLIC TYPE = RECORD [ currentDie: DiePosition, -- die to return to upon "Continue" button enableStepper: BOOL _ FALSE, -- internal, enables sending commands to ElectroGlas enableTester: BOOL _ FALSE, -- enables sending commands to Tester enableSimulation: BOOL _ FALSE, -- enables Rosemary simulation waferFile: Viewer _ NIL, -- handle for waferFile text viewer run: Viewer _ NIL, -- handle for run text viewer wafer: Viewer _ NIL, -- handle for wafer text viewer die: Viewer _ NIL, -- handle for die text viewer cutSet: Viewer _ NIL, -- handle for cutSet text viewer stop: Stop _ dont, -- internal, state of control buttons backupToken: IO.STREAM, -- internal, file stream parsing testInProgress: BOOL _ FALSE, -- internal, button monitor testButtonList: LIST OF Buttons.Button, -- internal, list of registered test buttons inStream: IO.STREAM _ NIL, -- wafer file input stream currentTestProc: ICTestNew.TestProc, port: Ports.Port, cellType: Core.CellType, forceGroups: IMSTester.ForceGroups, acquireGroups: IMSTester.AcquireGroups, buffer: IMSTester.Buffer, forceTab: RefTab.Ref, acquireTab: RefTab.Ref, cycle: IMSTester.Cycle, viewerout: IO.STREAM _ NIL --*** This should disappear*** ]; IMSGroup: ATOM = $IMSGroup; GroupData: TYPE = REF GroupDataRec; GroupDataRec: TYPE = RECORD[groupName: ROPE , format: FormatType, delay: NSec, width: NSec, hiDrive: REAL, loDrive: REAL, sample: NSec, threshold: REAL]; IMSChannel: ATOM = $IMSChannel; ChannelData: TYPE = REF ChannelDataRec; ChannelDataRec: TYPE = RECORD[board: Board, podTiming: PodTiming, channel: Channel]; BufferIndex: TYPE = REF BufferIndexRec; BufferIndexRec: TYPE = RECORD[b: Board, p: PodChannel]; <> forceBoardToSlot: REF BoardToSlot; acquireBoardToSlot: REF BoardToSlot; BoardToSlot: TYPE = ARRAY Board OF IMSTester.SlotNumber; <> progBoard: REF ProgBoard; ProgBoard: TYPE = ARRAY Board OF BOOL; alwaysDefineGroups: BOOL _ FALSE; -- for debugging alwaysDefinePort: BOOL _ FALSE; -- for debugging 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 strings firstColumn: NAT = 0*pointsPerInch; -- horizontal space to second column of buttons secondColumn: NAT = 2*pointsPerInch; -- horizontal space to second column of buttons thirdColumn: NAT = 4*pointsPerInch; -- horizontal space to third column of buttons Column: TYPE = NAT [0..2); MakeStandardViewer: PUBLIC PROC [testButtons: ICTestNew.TestButtonsCreateProc, cellType: Core.CellType, name: ROPE _ NIL, clientHandle: REF ANY _ NIL] = { viewer: Viewer; height: CARDINAL; height _ MakeStandardButtons[viewer _ Containers.Create[[-- construct the outer container name: Rope.Concat["IC Test Tool - ", name], iconic: FALSE, column: left, scrollable: FALSE ]], 0, testButtons, cellType, clientHandle]; ViewerOps.SetOpenHeight[viewer, height]; ViewerOps.PaintViewer[viewer, all]; }; MakeStandardButtons: PUBLIC PROC [viewer: ViewerClasses.Viewer, height: CARDINAL, testButtons: ICTestNew.TestButtonsCreateProc, cellType: Core.CellType, clientHandle: REF ANY _ NIL] RETURNS [newHeight: CARDINAL] = { CreateTestButton: PUBLIC PROC [buttonName: ROPE, proc: ICTestNew.TestProc] = { first: BOOLEAN _ h.testButtonList = NIL; testHandle: TestHandle _ NEW[TestHandleRec _ [h, proc]]; h.testButtonList _ CONS[Buttons.Create[info: [name: buttonName, wx: column*2*pointsPerInch, wy: height, ww: 0,wh: entryHeight, parent: viewer, border: TRUE], clientData: testHandle, proc: TestButton], h.testButtonList]; height _ height + entryHeight + entryVSpace; IF first THEN { h.currentTestProc _ proc; Buttons.SetDisplayStyle[h.testButtonList.first, $BlackOnGrey]; }; IF column = LAST[Column] THEN { column _ 0; height _ height + entryHeight + entryVSpace; } ELSE column _ column+1; }; rule: Rules.Rule; h: Handle; column: Column _ 0; h _ NEW[ICTestRec]; h.cellType _ cellType; h.waferFile _ ChoiceButtons.BuildTextPrompt[viewer, firstColumn, height, "Wafer File:", "SingleDie.dat", NIL, 7*pointsPerInch].textViewer; height _ height + entryHeight + entryVSpace; h.run _ ChoiceButtons.BuildTextPrompt[viewer, firstColumn, height, "Run:", NIL, NIL, 1*pointsPerInch].textViewer; [] _ Buttons.Create[info: [name: "Start Test", wx: secondColumn, wy: height, ww: 0,wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: StartTest]; [] _ Buttons.Create[info: [name: "Interrupt", wx: thirdColumn, wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: Interrupt]; height _ height + entryHeight + entryVSpace; h.wafer _ ChoiceButtons.BuildTextPrompt[viewer, firstColumn, height, "Wafer:", NIL, NIL, 1*pointsPerInch].textViewer; [] _ Buttons.Create[info: [name: "Abort Die", wx: secondColumn, wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, fork: FALSE, proc: AbortDie]; [] _ Buttons.Create[info: [name: "Continue", wx: thirdColumn, wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: Continue]; height _ height + entryHeight + entryVSpace; h.die _ ChoiceButtons.BuildTextPrompt[viewer, firstColumn, height, "Die:", NIL, NIL, 1*pointsPerInch].textViewer; [] _ Buttons.Create[info: [name: "Abort Wafer", wx: secondColumn, wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: AbortWafer, guarded: TRUE]; [] _ Buttons.Create[info: [name: "Enable Tester", wx: thirdColumn, wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: EnableTester]; height _ height + entryHeight + entryVSpace; h.cutSet _ ChoiceButtons.BuildTextPrompt[viewer, firstColumn, height, "Cut Set:", NIL, NIL, 1*pointsPerInch].textViewer; [] _ Buttons.Create[info: [name: "Abort Test", wx: secondColumn, wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: AbortTest, guarded: TRUE]; [] _ Buttons.Create[info: [name: "Enable Stepper", wx: thirdColumn, wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: EnableStepper]; height _ height + entryHeight + entryVSpace/2; rule _ Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]; Containers.ChildXBound[viewer, rule]; height _ height + entryHeight + entryVSpace/2; testButtons[CreateTestButton]; height _ height + entryHeight + entryVSpace/2; rule _ Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]; Containers.ChildXBound[viewer, rule]; [ , h.viewerout] _ ViewerIO.CreateViewerStreams[name: "ICTestTypescript", viewer:ViewerOps.CreateViewer[flavor: $TypeScript, info:[parent: viewer, wy: height+2, ww: 7*pointsPerInch, wh: 56 * entryHeight, scrollable: TRUE, border: FALSE]]]; height _ height + 10 * entryHeight; height _ height + entryHeight + entryVSpace/2; RETURN[height]; }; TestButton: Buttons.ButtonProc = { t: TestHandle _ NARROW[clientData]; h: Handle _ t.h; selectedButton: Viewer _ NARROW[parent]; FOR l: LIST OF Buttons.Button _ h.testButtonList, l.rest WHILE l#NIL DO Buttons.SetDisplayStyle[l.first, IF l.first = selectedButton THEN $BlackOnGrey ELSE $BlackOnWhite]; ENDLOOP; h.currentTestProc _ t.proc; }; DefineGroup: PUBLIC PROC [wire: Core.Wire, groupName: ROPE _ NIL, format: FormatType, delay: NSec _ 0, width: NSec _ 0, hiDrive: REAL _ 2.4, loDrive: REAL _ 0.4, sample: NSec _ 0, threshold: REAL _ 1.4] = { groupData: GroupData _ NEW[GroupDataRec _ [groupName, format, delay, width, hiDrive, loDrive, sample, threshold]]; CoreProperties.PutWireProp[wire, IMSGroup, groupData]; }; DefineChannel: PUBLIC PROC [atomicWire: Core.Wire, board: Board, podTiming: PodTiming, channel: Channel _ 0] = { channelData: ChannelData _ NEW[ChannelDataRec _ [board, podTiming, channel]]; IF atomicWire.size # 0 THEN ERROR; CoreProperties.PutWireProp[atomicWire, IMSChannel, channelData]; }; NextChannel: PUBLIC PROC [board: Board, podTiming: PodTiming, channel: Channel] RETURNS [newBoard: Board, newPodTiming: PodTiming, newChannel: Channel] = { IF channel=LAST[ICTestNew.Channel] THEN IF podTiming=B THEN IF board=LAST[ICTestNew.Board] THEN ERROR ELSE {board _ board + 1; podTiming _ A; channel _ 0} ELSE {podTiming _ B; channel _ 0} ELSE channel _ channel + 1; RETURN[board, podTiming, channel]; }; 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.viewerout, "\nRun %g", IO.rope[ViewerTools.GetContents[h.run]]]; }; IF done THEN { IO.Close[h.inStream]; 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.viewerout, "\nWafer %g ", IO.rope[ViewerTools.GetContents[h.wafer]]]; IF h.enableStepper THEN { EGlas.LampOn[]; IF h.testInProgress THEN EGlas.Load[]; --don't load wafer first time } ; }; }; }; NextDie: PROC [h: Handle] RETURNS [done: BOOLEAN _ FALSE] = { Eval: PROC [evalCycleType: ICTestNew.EvalCycleType] = { -- IF h.enableSimulation THEN Rosemary.Settle[Rosemary.InstantiateCellType[h.cellType, h.port]]; IF h.enableTester AND evalCycleType = force THEN ForceDataToIMS[h] ELSE AcquireDataToIMS[h]; }; 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.x], IO.int[h.currentDie.y]]]; IO.PutF[h.viewerout, "Die (%g,%g) ", IO.int[h.currentDie.x], IO.int[h.currentDie.y]]; }; }; IF NOT done THEN { h.stop _ dont; h.testInProgress _ TRUE; IF h.enableStepper THEN { EGlas.Seek[h.currentDie.x, h.currentDie.y]; EGlas.ZUp[]; EGlas.LampOff[]; }; h.currentTestProc[h.port, Eval]; <<{p: PROC ~ {h.currentTestProc[h]}; CedarProcess.DoWithPriority[priority: foreground, action: p]};>> IF h.enableStepper THEN EGlas.LampOn[]; }; }; 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; h.testInProgress _ FALSE; }; StartTest: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; IF NOT h.testInProgress THEN { h: Handle _ NARROW[clientData]; done: BOOLEAN _ FALSE; 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]; h.stop _ abortDie; }; AbortWafer: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; h.stop _ abortWafer; }; AbortTest: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; h.stop _ interrupt; h.testInProgress _ FALSE; }; EnableTester: Buttons.ButtonProc = { h: Handle _ NARROW[clientData]; selectedButton: Viewer _ NARROW[parent]; h.enableTester _ NOT h.enableTester; Buttons.SetDisplayStyle[selectedButton, IF h.enableTester THEN $BlackOnGrey 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 $BlackOnGrey ELSE $BlackOnWhite]; }; 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]; }; }; Message: PROC [rope: ROPE] = { MessageWindow.Append[rope, TRUE]; MessageWindow.Blink[]; MessageWindow.Append[rope, TRUE]; }; AcquireDataToIMS: PROC [h: Handle] = { }; ForceDataToIMS: PROC [h: Handle] = { PortToBuffer: RefTab.EachPairAction = { port: Ports.Port _ NARROW[key]; index: BufferIndex _ NARROW[val]; board: Board _ index.b; podChannel: PodChannel _ index.p; drive: BOOL _ IF port.d=force THEN FALSE ELSE TRUE; SELECT port.type FROM l => { SELECT port.l FROM L => {h.buffer[h.cycle][board][podChannel].force _ FALSE; h.buffer[h.cycle][board][podChannel].inhibit _ FALSE}; H => {h.buffer[h.cycle][board][podChannel].force _ TRUE; h.buffer[h.cycle][board][podChannel].inhibit _ FALSE}; X => h.buffer[h.cycle][board][podChannel].inhibit _ TRUE; ENDCASE => ERROR; }; ls => { FOR i: NAT IN [0..port.ls.size) DO SELECT port.ls[i] FROM L => {h.buffer[h.cycle][board][podChannel].force _ FALSE; h.buffer[h.cycle][board][podChannel].inhibit _ FALSE}; H => {h.buffer[h.cycle][board][podChannel].force _ TRUE; h.buffer[h.cycle][board][podChannel].inhibit _ FALSE}; X => h.buffer[h.cycle][board][podChannel].inhibit _ TRUE; ENDCASE => ERROR; IF podChannel > 15 THEN {podChannel _ 0; board _ board+1} ELSE podChannel _ podChannel+1; ENDLOOP; }; b => {h.buffer[h.cycle][board][podChannel].force _ port.b; h.buffer[h.cycle][board][podChannel].inhibit _ drive}; bs => { FOR i: NAT IN [0..port.bs.size) DO h.buffer[h.cycle][board][podChannel].force _ port.bs[i]; h.buffer[h.cycle][board][podChannel].inhibit _ drive; IF podChannel > 15 THEN {podChannel _ 0; board _ board+1} ELSE podChannel _ podChannel+1; ENDLOOP; }; c => { mask: CARDINAL _ 1; end: NAT _ Basics.bitsPerWord*SIZE[CARDINAL]-port.fieldStart; FOR i:NAT IN [0..end) DO h.buffer[h.cycle][board][podChannel].force _ Basics.BITAND[port.c, mask]#0; h.buffer[h.cycle][board][podChannel].inhibit _ drive; IF i = end-1 THEN EXIT; IF podChannel >= 15 THEN {podChannel _ 0; board _ board+1} ELSE podChannel _ podChannel+1; mask _ mask*2; ENDLOOP; }; lc => { mask: LONG CARDINAL _ 1; end: NAT _ Basics.bitsPerWord*SIZE[LONG CARDINAL]-port.fieldStart; FOR i:NAT IN [0..Basics.bitsPerWord*SIZE[LONG CARDINAL]-port.fieldStart) DO h.buffer[h.cycle][board][podChannel].force _ Basics.DoubleAnd[[lc[port.lc]], [lc[mask]]].lc#0; h.buffer[h.cycle][board][podChannel].inhibit _ drive; IF i = end-1 THEN EXIT; IF podChannel >= 15 THEN {podChannel _ 0; board _ board+1} ELSE podChannel _ podChannel+1; mask _ mask*2; ENDLOOP; }; ENDCASE => ERROR; RETURN[FALSE]; }; [] _ RefTab.Pairs[h.forceTab, PortToBuffer]; IMSTester.SetIMSMemory[h.forceGroups, h.buffer, 1, 0]; }; Init: PROC[h: Handle] = { MakePodTimingGroup: Ports.EachWirePortPairProc = { <> <<>> c: ChannelData; FindFirstChannel: CoreOps.EachWireProc = { chan: ChannelData; c _ NEW[ChannelDataRec _ [LAST[Board], LAST[PodTiming], LAST[Channel]]]; IF wire.size = 0 AND (chan _ NARROW[CoreProperties.GetWireProp[wire, IMSChannel]])#NIL THEN { IF chan.board < c.board THEN {c.board _ chan.board; c.podTiming _ chan.podTiming; c.channel _ chan.channel} ELSE IF chan.board = c.board THEN { IF chan.podTiming < c.podTiming THEN {c.podTiming _ chan.podTiming; c.channel _ chan.channel} ELSE IF chan.podTiming = c.podTiming THEN IF chan.channel < c.channel THEN c.channel _ chan.channel; }; }; }; <> IF port#NIL THEN IF port.type#composite AND NOT RefTab.Fetch[x: mapTab, key: port].found AND wire.size#0 THEN { [] _ CoreOps.VisitWire[wire, FindFirstChannel]; IF NOT RefTab.Insert[x: mapTab, key: port, val: NEW[BufferIndexRec _ [c.board, (IF c.podTiming = A THEN 0 ELSE 8) + c.channel]]] THEN ERROR; }; <> IF wire.size = 0 AND NOT RefTab.Fetch[x: visitTab, key: wire].found AND (c _ NARROW[CoreProperties.GetWireProp[wire, IMSChannel]])#NIL THEN { IF port#NIL THEN IF port.type=composite THEN ERROR ELSE IF NOT RefTab.Insert[x: mapTab, key: port, val: NEW[BufferIndexRec _ [c.board, (IF c.podTiming = A THEN 0 ELSE 8) + c.channel]]] THEN ERROR; IF NOT RefTab.Insert[x: visitTab, key: wire, val: $Visited] THEN ERROR; FOR l: PodTimingGroups _ podTimingGroups, l.rest WHILE l#NIL DO IF l.first.module.board = c.board AND l.first.podTiming = c.podTiming THEN { FOR p: IMSTester.Pins _ l.first.pins, p.rest WHILE p#NIL DO IF p.first.channel = c.channel THEN ERROR; --channel assigned twice ENDLOOP; l.first.pins _ CONS[NEW[IMSTester.PinRec _ [ channel: c.channel, signalName: NARROW[CoreProperties.GetWireProp[wire, CoreOps.nameProp]], packagePin: 0]], l.first.pins]; EXIT; }; REPEAT FINISHED => podTimingGroups _ CONS[NEW[IMSTester.PodTimingGroupRec _ [ module: NEW[IMSTester.ModuleRec _ [ slot: boardToSlot[c.board], board: c.board, threshold: g.threshold, hiDrive: g.hiDrive, loDrive: g.loDrive]], podTiming: c.podTiming, pins: LIST[NEW[IMSTester.PinRec _ [ channel: c.channel, signalName: NARROW[CoreProperties.GetWireProp[wire, CoreOps.nameProp]], packagePin: 0]]]]], podTimingGroups]; ENDLOOP; }; }; LimitGroupSize: PROC [groups: PodTimingGroups] 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 TRUSTED {channels _ channels + List.Length[LOOPHOLE[p.first.pins]]}; addToGroup _ channels <= 32 AND NOT progBoard[p.first.module.board]; IF newGroup#NIL THEN addToGroup _ addToGroup AND NOT progBoard[newGroup.first.module.board]; IF addToGroup THEN newGroup _ CONS[p.first, newGroup] ELSE { <> 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]; }; 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]; }; FindForceGroups: Ports.EachWirePortPairProc = { <> listOfGroups: LIST OF PodTimingGroups; char: CHAR; podTimingGroups _ NIL; char _ 'A; IF (g _ NARROW[CoreProperties.GetWireProp[wire, IMSGroup]]) # NIL THEN { [] _ Ports.VisitBinding[wire, port, MakePodTimingGroup]; listOfGroups _ LimitGroupSize[podTimingGroups]; FOR l: LIST OF PodTimingGroups _ listOfGroups, l.rest WHILE l#NIL DO h.forceGroups _ CONS[NEW[IMSTester.ForceGroupRec _ [IO.PutFR["F%g%g", IO.char[char], IO.rope[g.groupName]], l.first, g.format, g.delay, g.width]], h.forceGroups]; char _ char+1; ENDLOOP; }; }; FindAcquireGroups: Ports.EachWirePortPairProc = { <> listOfGroups: LIST OF PodTimingGroups; char: CHAR; podTimingGroups _ NIL; char _ 'A; IF (g _ NARROW[CoreProperties.GetWireProp[wire, IMSGroup]]) # NIL THEN { [] _ Ports.VisitBinding[wire, port, MakePodTimingGroup]; listOfGroups _ LimitGroupSize[podTimingGroups]; FOR l: LIST OF PodTimingGroups _ listOfGroups, l.rest WHILE l#NIL DO h.acquireGroups _ CONS[NEW[IMSTester.AcquireGroupRec _ [IO.PutFR["A%g%g", IO.char[char], IO.rope[g.groupName]], l.first, g.sample]], h.acquireGroups]; char _ char+1; ENDLOOP; }; }; visitTab, mapTab: RefTab.Ref; g: GroupData; boardToSlot: REF BoardToSlot; podTimingGroups: PodTimingGroups; filename: ROPE; filename _ ViewerTools.GetContents[h.waferFile]; h.inStream _ FS.StreamOpen[filename ! FS.Error => {Message[IO.PutFR["Wafer file: %g not found", IO.rope[filename]]]; CONTINUE}]; IF h.enableStepper THEN EGlas.Init[]; IF h.enableTester OR h.enableSimulation THEN h.port _ Ports.CreatePort[h.cellType.public]; IF (h.enableTester AND CoreProperties.GetCellTypeProp[h.cellType, $GroupsDefined]=NIL) OR alwaysDefineGroups THEN { h.forceGroups _ NIL; h.acquireGroups _ NIL; h.buffer _ NEW[IMSTester.BufferRec[1]]; h.cycle _ 0; IMSTester.Initialize[]; visitTab _ RefTab.Create[]; mapTab _ RefTab.Create[]; boardToSlot _ forceBoardToSlot; [] _ Ports.VisitBinding[h.cellType.public, h.port, FindForceGroups]; h.forceTab _ mapTab; visitTab _ RefTab.Create[]; mapTab _ RefTab.Create[]; boardToSlot _ acquireBoardToSlot; [] _ Ports.VisitBinding[h.cellType.public, h.port, FindAcquireGroups]; h.acquireTab _ mapTab; IMSTester.DefineGroups[h.forceGroups, h.acquireGroups]; h.buffer _ NEW[IMSTester.BufferRec[1]]; h.buffer[0] _ NEW[IMSTester.CycleDataRec]; CoreProperties.PutCellTypeProp[h.cellType, $GroupsDefined, $True]; }; }; Cleanup: PROC [h: Handle] = { IF h.enableStepper THEN EGlas.LampOn[]; IF h.enableTester THEN IMSTester.Stop[]; ---***only for debugging }; CheckStop: PUBLIC PROC [h: Handle] = { SELECT h.stop FROM dont => NULL; abortDie => ERROR AbortDieSignal; abortWafer => ERROR AbortWaferSignal; interrupt => ERROR InterruptSignal; ENDCASE => ERROR; }; END.