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]; 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. ICTestNewImpl.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 December 19, 1985 4:47:13 pm PST The array element forceBoardToSlot[n] should contain the slot number of the nth force board. Numbering of slots is sequential stating at slot 1 in the Master mainframe and ending with slot 48 in the third Slave mainframe. This information is intended to be initialized from the interpreter at runtime to allow dynamic assignment of modules to slots. acquireBoardToSlot is used in a similar manner. The array element progBoard[n] should be TRUE if either the force or acquire module corresponding to board n has programmable drive levels or threshold levels. {p: PROC ~ {h.currentTestProc[h]}; CedarProcess.DoWithPriority[priority: foreground, action: p]}; Searches the wire below the point where the group property was found. If a port leaf is reached which correponds to a composite wire, map the channels of the composite wire to the output buffer but don't add to PodTimingGroup. If a unique atomic wire is found that has the "IMSChannel" property put it in the right place in a PodTimingGroup. If there is a corresponding leaf port, map it to the output buffer. Case 1: The port is a unique leaf node and the corresponding wire is composite. Make the entry in the mapTab to connect the port value and the buffer to the IMS. Case 2: The wire is unique and atomic and has the "IMSChannel" property. Splits up groups which are larger that the IMS maximum of 32 channels into subgroups. Also splits up groups which span programmable 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 the current wire has the "IMSGroup" property then makes the PodTimingGroup for the wire below, and adds it to the list of force groups. Same as above but for acquire groups. Κ|˜šœ™Icodešœ Οmœ1™Jšœžœ #˜Jšœžœ $˜>Jšœ žœ /˜TJšœžœ /˜UJšœ žœ .˜SJšœž œ˜J˜šΟnœžœžœOžœžœžœžœžœ˜šJ˜Jšœžœ˜emphasisšœ9 œ˜[Jšœ+˜+Jšœžœ˜Jšœ ˜ Jšœ žœ˜Jšœ(˜(—Jšœ(˜(Jšœ#˜#J˜J˜—š‘œž œ(žœWžœžœžœžœ žœ˜Χš‘œž œžœ˜NJšœžœžœ˜(Jšœžœ˜8šœžœ(˜?Jšœ'˜'Jšœ˜Jšœžœ@˜\—Jšœ,˜,šžœžœ˜Jšœ˜Jšœ>˜>J˜—šžœ žœ žœ˜Jšœ ˜ Jšœ,˜,Jšœžœ˜—J˜J˜—J˜Jšœ ˜ Jšœ˜J˜Jšœžœ ˜J˜J˜Jšœižœ˜ŠJ˜Jšœ,˜,JšœKžœžœ˜qšœ.˜.Jšœ˜Jšœ˜Jšœžœ#˜?—Jšœ{žœ#˜’J˜Jšœ,˜,JšœOžœžœ˜ušœ-˜-JšœNžœžœ˜—Jšœzžœ"˜ J˜Jšœ,˜,JšœKžœžœ˜qJšœ~žœ-žœ˜΅Jšœžœ&˜©J˜Jšœ,˜,JšœRžœžœ˜xJšœ}žœ,žœ˜³Jšœ€žœ'˜«J˜Jšœ.˜.JšœH˜Hšœ%˜%J˜—Jšœ.˜.Jšœ˜J˜Jšœ.˜.JšœH˜HJšœ%˜%J˜JšœΨžœ žœ˜οJšœ#˜#Jšœ.˜.Jšžœ ˜J˜J˜—š‘ œ˜"Kšœžœ ˜#K˜Kšœžœ ˜(š žœžœžœ+žœžœž˜GKšœ!žœžœžœ˜cKšžœ˜—Kšœ˜Kšœ˜K˜—š ‘ œž œž œAžœžœ%žœ ˜ΞKšœžœX˜rKšœ6˜6J˜J˜—š‘ œž œV˜pKšœžœ/˜MKšžœžœžœ˜"Kšœ@˜@J˜J˜—š‘ œž œ8žœD˜›šžœ žœž˜'šžœ ž˜Kšžœžœžœž˜)Kšžœ0˜4—Kšžœ˜!—Kšžœ˜Kšžœ˜"K˜K˜—š‘œžœ˜š ‘ œžœ žœžœžœ˜6Kšœžœžœžœžœžœžœžœ!˜]Kšœžœ˜Kšœ˜—š ‘ œžœžœžœžœ˜/Kšœ˜Kšœ˜—š ‘œžœ žœžœžœ˜=Kšœžœ˜Kšœžœžœ˜ šžœžœ˜šžœžœž˜Kšœžœžœžœ˜=š žœžœžœžœžœž˜1Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšžœ žœ˜KšžœEžœ˜R—Kšžœ˜—šžœžœžœ˜šœžœ˜Kšžœžœžœ ˜3—KšžœM˜Ošžœžœ˜Kšœ˜Kšžœžœ ˜DKšœ˜—Kšœ˜—K˜—Kšœ˜—š ‘œžœ žœžœžœ˜=š‘œžœ-˜7KšžœžœC˜`šžœžœžœ˜BKšžœ˜—K˜K˜—Kšœžœ˜Kšœžœžœ˜ šžœžœ˜šžœžœž˜Kšœžœžœžœ˜=š žœžœžœžœžœ žœž˜1Kšœžœ˜(Kšœžœ˜(šœžœ˜2Kšžœžœžœ˜,—Kšžœ žœ˜Kšžœ:žœ˜G—Kšžœ˜—šžœžœžœ˜Jšœžœ ˜Kšœžœžœžœ˜dKšžœS˜UK˜—K˜—K˜šžœžœžœ˜K˜Jšœžœ˜šžœžœ˜Kšœ+˜+Kšœ ˜ Kšœ˜K˜—Kšœ ˜ K•StartOfExpansion3[priority: CedarProcess.Priority, action: PROC]šœžœY™aKšžœžœ˜'K˜—K˜K˜—šžœžœž˜šžœžœ žœžœ˜šžœžœ ž ˜šžœ ˜Kšœžœ˜Kšœžœž ˜#Kšžœ˜—Kšžœ˜—Kšžœ˜——Kšœžœ˜Kšœ˜K˜—š‘ œ˜!Kšœ žœ ˜šžœžœžœ˜Kšœ žœ ˜Kšœžœžœ˜Kšœ˜Kš žœžœžœžœ $˜SK˜Jšœžœ˜(Kšœ ˜ K˜—Kšœ˜K˜—š‘œ˜ Kšœ žœ ˜Kšœ˜Kšœ˜K˜—š‘ œ˜"Kšœ žœ ˜Kšœ˜Kšœ˜K˜—š‘ œ˜!Kšœ žœ ˜Kšœ˜Kšœžœ˜Kšœ˜K˜—š‘ œ˜$Kšœ žœ ˜Kšœžœ ˜(Kšœžœ˜$Kšœ(žœžœžœ˜`Kšœ˜K˜—š‘ œ˜%Kšœ žœ ˜Kšœžœ ˜(Kšœžœ˜&Kšœ(žœžœžœ˜aKšœ˜K˜—š‘ œ˜!Kšœ žœ ˜Kšœ˜Kšœ˜K˜—š‘œ˜ Kšœ žœ ˜šžœžœžœ˜3Kšœžœ˜(Kšœ ˜ K˜—Kšœ˜K˜—š‘œžœžœ˜Kšœžœ˜!Kšœ˜Kšœžœ˜!Kšœ˜K˜—š‘œžœ˜&Kšœ˜K˜—š‘œžœ˜$š‘ œ˜'Kšœžœ˜Kšœžœ˜!Kšœ˜Kšœ!˜!Kš œžœžœžœžœžœžœ˜3šžœ ž˜šœ˜šžœž˜šœ3žœ˜9Kšœ/žœ˜6—šœ3žœ˜8Kšœ/žœ˜6—Kšœ4žœ˜9Kšžœžœ˜—K˜—šœ˜šžœžœžœž˜"šžœ ž˜šœ3žœ˜9Kšœ/žœ˜6—šœ3žœ˜8Kšœ/žœ˜6—Kšœ4žœ˜9Kšžœžœ˜Kšžœžœ#žœ˜Y—Kšžœ˜—K˜—šœ:˜:Kšœ6˜6—šœ˜šžœžœžœž˜#Kšœ8˜8Kšœ5˜5Kšžœžœ#žœ˜YKšžœ˜—K˜—šœ˜Kšœžœ˜Kšœžœžœžœ˜=šžœžœžœ ž˜Kšœ4žœ˜KKšœ5˜5Kšžœ žœž˜Kšžœžœ#žœ˜ZKšœ˜Kšžœ˜—Kšœ˜—šœ˜Kšœž œ˜Kšœžœžœž œ˜Bš žœžœžœžœž œž˜KKšœ^˜^Kšœ5˜5Kšžœ žœž˜Kšžœžœ#žœ˜ZKšœ˜Kšžœ˜—K˜—Kšžœžœ˜—Kšžœžœ˜K˜K˜—Kšœ,˜,Kšœ6˜6Kšœ˜K˜—š‘œžœ˜š‘œ ˜2Kšœœ™œK™K˜K˜š‘œ˜*K˜Kš œžœžœ žœ žœ ˜Hš žœžœ žœ0žœžœ˜]šžœžœ˜KšœN˜Nšžœžœ˜#šžœž˜$Kšœ9˜9šžœžœžœ˜*Kšžœžœ˜:——K˜——K˜—K˜—K˜K™€šžœžœžœžœžœžœ*žœ žœ˜pK˜/Kš žœ*žœžœžœžœžœž˜ŒKšœ˜K˜—KšœH™Hšžœžœžœ,žœžœ0žœžœ˜š žœžœžœžœžœžœž˜7Kšžœžœ*žœžœžœžœžœž˜Œ—Kšžœžœ6žœžœ˜Gšžœ.žœžœž˜?šžœ žœ!žœ˜Lšžœ*žœžœž˜;Kšžœžœžœ ˜CKšžœ˜—šœžœžœ˜,Kšœ˜Kšœ žœ6˜HKšœ˜—Kšžœ˜K˜—šž˜šžœ˜ šœžœžœ ˜:šœžœ˜#Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜šœžœ˜#Kšœ˜Kšœ žœ5˜GKšœ%˜%————Kšžœ˜ —K˜—K˜K˜—š ‘œžœžœžœžœ˜bKšœ„™„Kšœ)˜)Kšœžœžœ˜+Kšœ žœ˜Kšœ žœ˜Kšœ ˜ Kšœ žœ˜Kšœžœ˜šžœ%žœžœž˜6Kšžœ$žœ˜DKšœžœžœ!˜DKš žœ žœžœžœžœ(˜\šžœ žœ žœžœ˜<šœ@™@Kšœžœ˜šžœ'žœžœž˜8Kšœžœ˜-Kšžœ˜—Kšœžœ˜1Kšœžœ ˜'K˜——Kšžœ˜—Kšœ2™2Kšœžœ˜š žœ žœžœžœ'žœžœž˜MKšœžœ˜-Kšžœ˜—Kšœžœ˜1K˜K˜—š‘œ ˜/KšœŠ™ŠKšœžœžœ˜&Kšœžœ˜ Kšœžœ˜Kšœ ˜ šžœžœ0žœžœ˜HKšœ8˜8Kšœ/˜/š žœžœžœ(žœžœž˜DKš œžœžœžœžœ žœK˜’Kšœ˜Kšžœ˜—Kšœ˜—K˜K˜—š‘œ ˜1Kšœ%™%Kšœžœžœ˜&Kšœžœ˜ Kšœžœ˜Kšœ ˜ šžœžœ0žœžœ˜HKšœ8˜8Kšœ/˜/š žœžœžœ(žœžœž˜DKš œžœžœžœžœ žœ;˜–Kšœ˜Kšžœ˜—Kšœ˜—K˜K˜—K˜Kšœ ˜ Kšœ žœ ˜Kšœ!˜!Kšœ ž˜K˜Kšœ0˜0šœ žœ˜%Kšžœžœ#žœ˜NKšžœ˜ —Kšžœžœ˜%Kšžœžœžœ.˜Zš žœžœ<žœžœžœ˜tKšœžœ˜Kšœžœ˜Kšœ žœ˜'K˜ Kšœ˜K˜Kšœ˜Kšœ˜Kšœ˜KšœD˜DKšœ˜K˜Kšœ˜Kšœ˜Kšœ!˜!KšœF˜FKšœ˜K˜Kšœ7˜7Kšœ žœ˜'Kšœžœ˜*JšœB˜BK˜—Kšœ˜K˜—š‘œžœ˜Kšžœžœ˜'Kšžœžœ+˜AK˜K˜—š‘ œž œ˜&šžœž˜Kšœžœ˜ Kšœ žœ˜!Kšœžœ˜%Kšœ žœ˜#Kšžœžœ˜—Kšœ˜K˜—Jšžœ˜J˜Kš ˜—…—X²{<