IMSTesterImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Gasbarro December 9, 1985 12:46:42 pm PST
Last Edited by: Neil Gunther December 18, 1985 3:00:10 pm PST
Last Edited by: Gasbarro May 8, 1986 10:06:23 am PDT
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 BOOLFALSE;
stop: PUBLIC BOOLFALSE;
-- Globals --
synOut: IO.STREAMNIL;
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: BOOLTRUE] = 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: BOOLFALSE;
timingChannel: BOOLFALSE;
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]]];
WriteDevice[IO.PutFR["RAD %g BIN", IO.rope[f.name]]];
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]]];
WriteDevice[IO.PutFR["RAD %g BIN", IO.rope[a.name]]];
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] = {
Starts looking for errors at startCycle and continues until "maxErrors" errors are found or lastCycle is reached.
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
IM$: find? seq 0 "" "???e"
find (Seq 2,...)
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;
IM$: mem? 2 COM
mem 2,Compare,"C 0000 M 00 C 00 C 00000002 FFFF 00 00 FFFFFFFF"," e"
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: BOOLTRUE] = 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.