<> <> <> <> <> <<>> DIRECTORY Basics, Convert, FS, GPIB, IMSTester, IO, RefText, Rope; IMSTesterImpl: CEDAR MONITOR IMPORTS Basics, Convert, FS, GPIB, IO, RefText, Rope EXPORTS IMSTester = BEGIN OPEN IMSTester; IMS: GPIB.DeviceAddr = 1; statusIMS: NAT; maxPktSize: NAT = 512; channelsPerGroup: NAT = 32; IMSError: PUBLIC SIGNAL [msg: ROPE] = CODE; checkSyntax: PUBLIC BOOL _ FALSE; stop: PUBLIC BOOL _ FALSE; <<-- Globals -->> synOut: IO.STREAM _ NIL; validCycles: Cycle _ 0; --number of valid cycles in IMS memory forceBd, acquireBd, progBd: PACKED ARRAY SlotNumber OF BOOLEAN; Initialize: PUBLIC ENTRY PROC RETURNS [forceBoard, acquireBoard, programable: PACKED ARRAY SlotNumber OF BOOLEAN] = TRUSTED {{ -- the tester ENABLE UNWIND => NULL; rope: ROPE; stop _ FALSE; IF checkSyntax THEN synOut _ FS.StreamOpen["IMSTester.synout", $create] ELSE IF GPIB.InitializeController[] THEN { GPIB.InterfaceClear[]; GPIB.SelectedDeviceClear[IMS]} ELSE {IMSError["GPIB Controller Error!"]; RETURN; }; WriteDevice["INIT"]; --sets IMS modules to power-up condition FOR n: SlotNumber IN SlotNumber DO WriteDevice[IO.PutFR["CON? %g", IO.int[n]]]; rope _ ReadDevice[]; IF rope=NIL THEN { FOR slot: SlotNumber IN SlotNumber DO forceBoard[slot] _ (slot < 8) OR ((slot > 10) AND ((slot MOD 2)=1)); --reflects the current configuration acquireBoard[slot] _ (slot>11) AND ((slot MOD 2)=0); programable[slot] _ slot=7 OR slot=22; ENDLOOP; } ELSE { forceBoard[n] _ Rope.Find[rope, "STM", 0, FALSE]#-1; acquireBoard[n] _ Rope.Find[rope, "ACQ", 0, FALSE]#-1; programable[n] _ Rope.Find[rope, "PGM PGM", 0, FALSE]#-1 }; ENDLOOP; forceBd _ forceBoard; acquireBd _ acquireBoard; progBd _ programable; }}; RunDiagnostics: PUBLIC ENTRY PROC [extended: BOOL _ TRUE] = TRUSTED {{ <<-- What about looping? Use IMSCommander for serious interrogation.>> ENABLE UNWIND => NULL; diagComplete: NAT = 196; IF extended THEN WriteDevice["DIAG ALL, EXT, ONCE"] -- wipes out pattern memory! ELSE WriteDevice["DIAG ALL, NORMAL, ONCE"]; IF NOT checkSyntax THEN UNTIL statusIMS = diagComplete DO statusIMS _ LOOPHOLE[GPIB.SelectedReadSerialPoll[IMS]]; <<--store diag results, someday(sigh!)>> ENDLOOP; WriteDevice["DIAG END"]; }}; DefineGroups: PUBLIC ENTRY PROC [forceGroups: ForceGroups, acquireGroups: AcquireGroups] = { ENABLE UNWIND => NULL; podTiming: PodTiming; sentBanner: BOOL _ FALSE; timingChannel: BOOL _ FALSE; rootName, name: ROPE; length: NAT; FOR fg: ForceGroups _ forceGroups, fg.rest UNTIL fg=NIL DO length _ 0; sentBanner _ FALSE; FOR ptg: PodTimingGroups _ fg.first.podTimingGroups, ptg.rest UNTIL ptg=NIL DO podTiming _ ptg.first.podTiming; timingChannel _ podTiming=AT OR podTiming=BT; IF NOT sentBanner THEN { sentBanner _ TRUE; IF timingChannel THEN { WriteDevice[IO.PutFR["RES %g TIM #TXT", IO.rope[fg.first.name]]]; IF fg.first.format#RZ AND fg.first.format#R1 THEN IMSError["Illegal Format for Timing group"]; } ELSE WriteDevice[IO.PutFR["RES %g FOR #TXT", IO.rope[fg.first.name]]]; }; IF NOT forceBd[ptg.first.slot] THEN IMSError[IO.PutFR["No force board in slot %g for Force group %g", IO.int[ptg.first.slot], IO.rope[fg.first.name]]]; IF fg.first.programable AND NOT progBd[ptg.first.slot] THEN IMSError[IO.PutFR["Force board in slot %g for Force group %g is not programable", IO.int[ptg.first.slot], IO.rope[fg.first.name]]]; rootName _ SELECT podTiming FROM A=>"A", B=>"B", AT=>"AT", BT=>"BT", ENDCASE=>ERROR; FOR p: Pins _ ptg.first.pins, p.rest UNTIL p=NIL DO IF timingChannel AND p.first.channel#0 THEN IMSError["Can only assign channel 0 in A/B timing groups"]; IF (length _ length+1)>channelsPerGroup THEN IMSError[IO.PutFR["Force Group '%g' exceeded %g channels", IO.rope[fg.first.name], IO.int[channelsPerGroup]]]; name _ IF timingChannel THEN rootName ELSE IO.PutFR["%g%g", IO.rope[rootName], IO.int[p.first.channel]]; WriteDevice[IO.PutFR["%g %g %g %g", IO.card[ptg.first.slot], IO.rope[name], IO.rope[p.first.signalName], IO.card[p.first.packagePin]]]; ENDLOOP; ENDLOOP; WriteDevice["RES END"]; DefineParameters[fg: LIST[fg.first]]; ENDLOOP; FOR ag: AcquireGroups _ acquireGroups, ag.rest UNTIL ag=NIL DO length _ 0; WriteDevice[IO.PutFR["RES %g %g #TXT", IO.rope[ag.first.name], IO.rope[IF ag.first.compare THEN "COM" ELSE "ACQ"]]]; FOR ptg: PodTimingGroups _ ag.first.podTimingGroups, ptg.rest UNTIL ptg=NIL DO IF NOT acquireBd[ptg.first.slot] THEN IMSError[IO.PutFR["No acquire board in slot %g for Acquire group %g", IO.int[ptg.first.slot], IO.rope[ag.first.name]]]; IF ag.first.programable AND NOT progBd[ptg.first.slot] THEN IMSError[IO.PutFR["Force board in slot %g for Force group %g is not programable", IO.int[ptg.first.slot], IO.rope[ag.first.name]]]; IF ag.first.compare AND NOT forceBd[ptg.first.slot+1] THEN IMSError[IO.PutFR["No force board in slot %g for Compare group %g", IO.int[ptg.first.slot+1], IO.rope[ag.first.name]]]; IF ptg.first.podTiming=AT OR ptg.first.podTiming=BT THEN IMSError["Cannot assign AT or BT in an Acquire group"]; FOR p: Pins _ ptg.first.pins, p.rest UNTIL p=NIL DO IF (length _ length+1)>channelsPerGroup THEN IMSError[IO.PutFR["Acquire Group '%g' exceeded %g channels", IO.rope[ag.first.name], IO.int[channelsPerGroup]]]; WriteDevice[IO.PutFR["%g %g%g %g %g", IO.card[ptg.first.slot], IO.rope[SELECT ptg.first.podTiming FROM A=>"A", B=>"B", ENDCASE=> ERROR], IO.card[p.first.channel], IO.rope[p.first.signalName], IO.card[p.first.packagePin]]]; ENDLOOP; ENDLOOP; WriteDevice["RES END"]; DefineParameters[ag: LIST[ag.first]]; ENDLOOP; }; RedefineGroups: PUBLIC ENTRY PROC [forceGroups: ForceGroups _ NIL, acquireGroups: AcquireGroups _ NIL] = { DefineParameters[fg: forceGroups, ag: acquireGroups]; }; DefineParameters: PRIVATE INTERNAL PROC [fg: ForceGroups _ NIL, ag: AcquireGroups _ NIL] = { FOR fgl: ForceGroups _ fg, fgl.rest WHILE fgl#NIL DO f: ForceGroup _ fgl.first; WriteDevice[IO.PutFR["FOR %g %g %gns %gns", IO.rope[f.name], IO.rope[SELECT f.format FROM NRZ=>"NRZ", DNRZ=>"DNRZ", RZ=>"RZ", R1=>"R1", RC=>"RC", ENDCASE=>"RI"], IO.int[f.delay], IO.int[f.width]]]; <> IF f.programable THEN { WriteDevice[IO.PutFR["HID %g %g", IO.rope[f.name], IO.real[f.hiDrive]]]; WriteDevice[IO.PutFR["LOD %g %g", IO.rope[f.name], IO.real[f.loDrive]]]; }; ENDLOOP; FOR agl: AcquireGroups _ ag, agl.rest WHILE agl#NIL DO a: AcquireGroup _ agl.first; WriteDevice[IO.PutFR["SAM %g %gns", IO.rope[a.name], IO.int[a.sample]]]; <> IF a.programable THEN WriteDevice[IO.PutFR["THR %g %g", IO.rope[a.name], IO.real[a.threshold]]]; ENDLOOP; }; SetCyclePeriod: PUBLIC ENTRY PROC [period: Period] = { ENABLE UNWIND => NULL; WriteDevice[IO.PutFR["CLK INT %gNS", IO.int[period]]]; }; SetIMSMemory: PUBLIC ENTRY PROC [forceGroups: ForceGroups, acquireGroups: AcquireGroups, buffer: Buffer, cycles: Cycle, halt: Cycle, jumps: Jumps _ NIL] = { ENABLE UNWIND => NULL; firstPTG: PodTimingGroup; firstControlBit: BOOL; vector: REF TEXT; bits: LONG CARDINAL; data: Data; validCycles _ cycles; vector _ RefText.ObtainScratch[maxPktSize]; vector.length _ 0; FOR now: Cycle IN [0..cycles) DO --build vector for this cycle IF stop THEN EXIT; vector _ RefText.AppendRope[vector, "MEM "]; vector _ RefText.AppendRope[vector, Convert.RopeFromCard[now]]; vector _ RefText.AppendRope[vector, " \""]; FOR fg: ForceGroups _ forceGroups, fg.rest UNTIL fg=NIL DO bits _ 0; firstPTG _ fg.first.podTimingGroups.first; firstControlBit _ buffer[now][firstPTG.board][(SELECT firstPTG.podTiming FROM A=>0, B=>8, AT=>16, BT=>17 ENDCASE=>ERROR)+firstPTG.pins.first.channel].inhibit; IF ~firstPTG.podTiming=AT AND ~firstPTG.podTiming=BT THEN { vector _ RefText.AppendChar[vector, IF firstControlBit THEN 'i ELSE 'f]; vector _ RefText.AppendChar[vector, ' ]; }; FOR ptg: PodTimingGroups _ fg.first.podTimingGroups, ptg.rest UNTIL ptg=NIL DO FOR p: Pins _ ptg.first.pins, p.rest UNTIL p=NIL DO bits _ bits*2; data _ buffer[now][ptg.first.board][(SELECT ptg.first.podTiming FROM A=>0, B=>8, AT=>16, BT=>17 ENDCASE=>ERROR)+p.first.channel]; IF firstControlBit#data.inhibit THEN IMSError[IO.PutFR["Force group %g is not strictly Force or Inhibit", IO.rope[fg.first.name]]]; IF data.forceData THEN bits _ bits+1; ENDLOOP; ENDLOOP; vector _ Convert.AppendCard[to: vector, from: bits, base: 16, showRadix: FALSE]; vector _ RefText.AppendChar[vector, ' ]; ENDLOOP; FOR ag: AcquireGroups _ acquireGroups, ag.rest UNTIL ag=NIL DO IF ag.first.compare THEN { bits _ 0; firstPTG _ ag.first.podTimingGroups.first; firstControlBit _ buffer[now][firstPTG.board][(SELECT firstPTG.podTiming FROM A=>0, B=>8, AT=>16, BT=>17 ENDCASE=>ERROR)+firstPTG.pins.first.channel].mask; vector _ RefText.AppendChar[vector, IF firstControlBit THEN 'm ELSE 'c]; vector _ RefText.AppendChar[vector, ' ]; FOR ptg: PodTimingGroups _ ag.first.podTimingGroups, ptg.rest UNTIL ptg=NIL DO FOR p: Pins _ ptg.first.pins, p.rest UNTIL p=NIL DO bits _ bits*2; data _ buffer[now][ptg.first.board][(SELECT ptg.first.podTiming FROM A=>0, B=>8, AT=>16, BT=>17 ENDCASE=>ERROR)+p.first.channel]; IF firstControlBit#data.mask THEN IMSError[IO.PutFR["Acquire group %g is not strictly Mask or Compare", IO.rope[ag.first.name]]]; IF data.compareData THEN bits _ bits+1; ENDLOOP; ENDLOOP; vector _ Convert.AppendCard[to: vector, from: bits, base: 16, showRadix: FALSE]; vector _ RefText.AppendChar[vector, ' ]; }; ENDLOOP; FOR l: Jumps _ jumps, l.rest WHILE l#NIL DO IF jumps.first.source=now THEN { IF halt=now THEN IMSError["Cannot Halt and Jump in same cycle!"]; vector _ RefText.AppendTextRope[vector, ": Goto "]; vector _ RefText.AppendRope[vector, IO.PutR1[IO.card[jumps.first.destination]]]; jumps _ jumps.rest; }; ENDLOOP; IF halt=now THEN vector _ RefText.AppendTextRope[vector, ": Halt"]; vector _ RefText.AppendRope[vector, IF checkSyntax THEN "\"\n" ELSE "\"\l"]; IF vector.length>(maxPktSize-100) THEN { --try not to go over maxPktSize WriteDevice[Rope.FromRefText[vector], now=cycles-1]; vector.length _ 0; }; REPEAT FINISHED => IF vector.length#0 THEN WriteDevice[Rope.FromRefText[vector], TRUE]; ENDLOOP; RefText.ReleaseScratch[vector]; }; ErrorCount: PUBLIC ENTRY PROC RETURNS [count: LONG CARDINAL] = { ENABLE UNWIND => NULL; s: IO.STREAM; IF checkSyntax THEN RETURN[0] ELSE { WriteDevice["FAIL?"]; s _ IO.RIS[ReadDevice[]]; IF NOT Rope.Equal[IO.GetTokenRope[s ! IO.EndOfStream => ERROR].token, "FAIL", FALSE] THEN ERROR; RETURN[IO.GetCard[s ! IO.EndOfStream => ERROR]]; }; }; GetErrors: PUBLIC ENTRY PROC [acquireGroups: AcquireGroups, buffer: Buffer, maxErrors: NAT, startCycle: Cycle, lastCycle: Cycle] RETURNS [errors: Errors] = { <> ENABLE UNWIND => NULL; s: IO.STREAM; err: Errors _ NIL; pinCount: NAT; mask, acquireData: LONG CARDINAL; expectData: Data; errCnt: NAT _ 0; IF validCycles=0 THEN RETURN[NIL]; IF lastCycle > (validCycles-1) THEN lastCycle _ validCycles-1; IF startCycle > (validCycles-1) THEN startCycle _ 0; IF NOT checkSyntax THEN WHILE startCycle <= lastCycle DO <> <> WriteDevice[IO.PutFR["FIND? SEQ %g", IO.card[startCycle]]]; s _ IO.RIS[ReadDevice[]]; IF NOT Rope.Equal[IO.GetTokenRope[s ! IO.EndOfStream => ERROR].token, "FIND", FALSE] THEN ERROR; IF NOT Rope.Equal[IO.GetTokenRope[s ! IO.EndOfStream => GOTO finished].token, "SEQ", FALSE] THEN ERROR; startCycle _ IO.GetCard[s ! IO.EndOfStream => ERROR]; IF startCycle>lastCycle THEN GOTO finished; <> <> WriteDevice[IO.PutFR["MEM? %g COM", IO.card[startCycle]]]; s _ IO.RIS[ReadDevice[! IO.EndOfStream => ERROR]]; WHILE ([]_s.GetChar[]) # '" DO ENDLOOP; --skip to opening quote FOR ag: AcquireGroups _ acquireGroups, ag.rest UNTIL ag=NIL DO --skip compare data [] _ IO.GetTokenRope[s ! IO.EndOfStream => ERROR]; --gets 'C or 'M designator [] _ IO.GetTokenRope[s ! IO.EndOfStream => ERROR]; --gets data ENDLOOP; FOR ag: AcquireGroups _ acquireGroups, ag.rest UNTIL ag=NIL DO --skip compare data pinCount _ 0; FOR ptg: PodTimingGroups _ ag.first.podTimingGroups, ptg.rest UNTIL ptg=NIL DO FOR p: Pins _ ptg.first.pins, p.rest UNTIL p=NIL DO pinCount _ pinCount+1; ENDLOOP; ENDLOOP; acquireData _ Convert.CardFromRope[IO.GetTokenRope[s ! IO.EndOfStream => ERROR].token, 16]; mask _ Basics.DoubleShift[[lc[1]], pinCount-1].lc; FOR ptg: PodTimingGroups _ ag.first.podTimingGroups, ptg.rest UNTIL ptg=NIL DO FOR p: Pins _ ptg.first.pins, p.rest UNTIL p=NIL DO expectData _ buffer[startCycle][ptg.first.board][(SELECT ptg.first.podTiming FROM A=>0, B=>8, AT=>16, BT=>17 ENDCASE=>ERROR)+p.first.channel]; IF NOT expectData.mask AND XOR[(Basics.DoubleAnd[[lc[acquireData]], [lc[mask]]].lc#0), expectData.compareData] THEN { err _ CONS[[startCycle, ag.first, ptg.first, p.first, expectData.compareData, NOT expectData.compareData], err]; errCnt _ errCnt+1; IF errCnt > maxErrors THEN GOTO finished; }; mask _ Basics.DoubleShift[[lc[mask]], -1].lc; ENDLOOP; ENDLOOP; ENDLOOP; startCycle _ startCycle+1; REPEAT finished => NULL; ENDLOOP; errors _ NIL; FOR l: Errors _ err, l.rest WHILE l#NIL DO --put list in increasing order errors _ CONS[l.first, errors]; ENDLOOP; }; Start: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; WriteDevice["START ALL"] }; Stop: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; WriteDevice["STOP ALL"]; --current test operations IF checkSyntax AND synOut#NIL THEN IO.Close[synOut]; }; Wait: PUBLIC ENTRY PROC = { <<-- for HALT to be executed or timeout>> ENABLE UNWIND => NULL; WriteDevice["WAIT ALL, 10s"]; }; XOR: PRIVATE INTERNAL PROC [a,b: BOOL] RETURNS [BOOL] = { RETURN[(a AND ~b) OR (~a AND b)] }; GetIMSStatusMsg: PRIVATE INTERNAL PROC RETURNS [msg: ROPE] = TRUSTED {{ errBuf: ROPE; IF checkSyntax THEN RETURN["GetIMSStatusMsg: No Status Message in Simulation."]; statusIMS _ LOOPHOLE[GPIB.SelectedReadSerialPoll[IMS]]; GPIB.WriteDevice[IMS, "Err?\l"]; errBuf_ GPIB.ReadDevice[IMS]; errBuf _ Rope.Substr[errBuf, Rope.Length["error \""], Rope.Length[errBuf]-3]; msg _ IO.PutFR["SRQ: %g; Error: %g", IO.card[statusIMS], IO.rope[errBuf]]; }}; WriteDevice: PRIVATE INTERNAL PROC [msg: ROPE, hold: BOOL _ TRUE] = TRUSTED {{ IF synOut=NIL THEN synOut _ FS.StreamOpen["IMSTester.synout", $create]; --check for NIL IF checkSyntax THEN synOut.PutF["%g\n", IO.rope[msg] ! IO.Error => {synOut _ FS.StreamOpen["IMSTester.synout", $create]; RETRY}] --handle the non-NIL but closed case ELSE GPIB.WriteDeviceBuffered[IMS, Rope.Concat[msg, "\l"], hold]; }}; ReadDevice: PRIVATE INTERNAL PROC RETURNS [memState: ROPE] = TRUSTED {{ IF NOT checkSyntax THEN RETURN[GPIB.ReadDevice[IMS]]; }}; END.