PinFinder:
CEDAR
PROGRAM
IMPORTS ChipTest, Commander, CommandTool,
IO, Process, ProcessExtras =
BEGIN
tester: ChipTest.Tester;
FindShort:
PROC
RETURNS [found:
BOOLEAN ←
FALSE, p1, p2: ChipTest.Channel ← 0] =
BEGIN OPEN ChipTest;
If p1 and p2 exist, then their representations differ in some bit position. This algorithm cycles through the bits in the representation of pin number, searching for some group of pins that causes a change in some other group of pins. As soon as this happens, we can identify the changees, and then turn the tables to find the changers.
d: RWChannelVecRef = NEW[ChannelVec];
FindHits:
PROC
RETURNS [count:
NAT ← 0, aHit: Channel ← 0] =
BEGIN
hits: ChannelVec;
input: ChannelVecRef;
[] ← tester.PutBBuf[trues];
[] ← tester.PutABuf[falses];
tester.Step[];
tester.Step[];
input ← tester.GetIBuf[];
FOR j: Channel
IN [
FIRST[Channel]..
LAST[Channel]]
DO
hits[j] ← d[j] AND NOT input[j];
ENDLOOP;
[] ← tester.PutABuf[trues];
tester.Step[];
tester.Step[];
input ← tester.GetIBuf[];
FOR j: Channel
IN [
FIRST[Channel]..
LAST[Channel]]
DO
IF hits[j] AND d[j] AND input[j] THEN {aHit ← j; count ← count+1};
ENDLOOP;
END;
FOR delta:
NAT ← 1, delta+delta
WHILE delta<=
LAST[Channel]
DO
hitCount: NAT;
FOR j: Channel
IN [
FIRST[Channel]..
LAST[Channel]]
DO
d[j] ← ((j MOD 2*delta)<delta);
ENDLOOP;
[] ← tester.PutDisables[d];
[hitCount, p1] ← FindHits[];
SELECT hitCount
FROM
>1 => {[] ← tester.PutDisables[trues]; RETURN};
=1 =>
BEGIN
FOR j: Channel
IN [
FIRST[Channel]..
LAST[Channel]]
DO
d[j] ← (j#p1);
ENDLOOP;
[] ← tester.PutDisables[d];
[hitCount, p2] ← FindHits[];
[] ← tester.PutDisables[trues];
found ← hitCount=1;
END;
ENDCASE => NULL;
ENDLOOP;
[] ← tester.PutDisables[trues];
END;
FindGround:
PROC
RETURNS [count:
NAT ← 0, p: ChipTest.Channel ← 0] =
BEGIN OPEN ChipTest;
trues: ChannelVecRef = NEW[ChannelVec ← ALL[TRUE]];
falses: ChannelVecRef = NEW[ChannelVec ← ALL[FALSE]];
input: ChannelVecRef;
[] ← tester.PutDisables[trues];
tester.Step[];
tester.Step[];
input ← tester.GetIBuf[];
FOR j: Channel
IN [
FIRST[Channel]..
LAST[Channel]]
DO
IF NOT input[j] THEN {p ← j; count ← count+1};
ENDLOOP;
END;
SetTester:
PROC [cmd: Commander.Handle] =
BEGIN
args: CommandTool.ArgumentVector = CommandTool.Parse[cmd: cmd];
tester ← ChipTest.OpenTester[(IF args.argc<2 THEN "" ELSE args[1])];
END;
WatchGround: Commander.CommandProc =
BEGIN
args: CommandTool.ArgumentVector = CommandTool.Parse[cmd: cmd];
in: IO.STREAM ← cmd.in;
out: IO.STREAM ← cmd.out;
oldCount: NAT;
oldP: ChipTest.Channel;
SetTester[cmd];
FOR pass:
INT ← 0, 1
DO
count: NAT;
p: ChipTest.Channel;
ProcessExtras.CheckForAbort[ ! ABORTED => EXIT ];
tester.Initialize[]; -- in case of power off/on cycle
[count: count, p: p] ← FindGround[];
SELECT count
FROM
0 =>
IF pass<1
OR oldCount#0
THEN
out.PutF["\nNo pin is grounded."];
1 =>
IF pass<1
OR oldCount#1
OR oldP#p
THEN
out.PutF["\nPin %d is grounded.", IO.int[p]];
ENDCASE =>
IF pass<1
OR oldCount#count
OR oldP#p
THEN
out.PutF["\nPin %d and %d others are grounded.", IO.int[p], IO.int[count-1]];
oldCount ← count;
oldP ← p;
Process.Pause[ticks: Process.MsecToTicks[1000] ! ABORTED => EXIT ];
ENDLOOP;
out.PutF["\n"];
END;
StepLoop: Commander.CommandProc =
BEGIN
trues: ChipTest.ChannelVecRef = NEW[ChipTest.ChannelVec ← ALL[TRUE]];
falses: ChipTest.ChannelVecRef = NEW[ChipTest.ChannelVec ← ALL[FALSE]];
SetTester[cmd];
DO
ProcessExtras.CheckForAbort[ ! ABORTED => EXIT ];
tester.Initialize[]; -- in case of power off/on cycle
tester.PutABDelay[0];
tester.PutAIDelay[0];
[] ← tester.PutDisables[falses];
[] ← tester.PutABuf[trues];
[] ← tester.PutBBuf[trues];
tester.Step[];
[] ← tester.PutBBuf[falses];
tester.Step[];
[] ← tester.PutABuf[falses];
tester.Step[];
[] ← tester.PutBBuf[trues];
tester.Step[];
Process.Yield[];
ENDLOOP;
END;
TestTester: Commander.CommandProc =
BEGIN
trues: ChipTest.ChannelVecRef = NEW[ChipTest.ChannelVec ← ALL[TRUE]];
falses: ChipTest.ChannelVecRef = NEW[ChipTest.ChannelVec ← ALL[FALSE]];
a: ChipTest.RWChannelVecRef = NEW[ChipTest.ChannelVec ← ALL[FALSE]];
b: ChipTest.RWChannelVecRef = NEW[ChipTest.ChannelVec ← ALL[FALSE]];
m: ChipTest.RWChannelVecRef = NEW[ChipTest.ChannelVec ← ALL[FALSE]];
e: ChipTest.RWChannelVecRef = NEW[ChipTest.ChannelVec ← ALL[FALSE]];
SetTester[cmd];
FOR i: ChipTest.Channel ← 0, (i+1)
MOD (
LAST[ChipTest.Channel]+1)
DO
Failure:
PROC [expected, was: ChipTest.ChannelVecRef] =
{cmd.out.PutF["{%g=>%g}", IO.bool[expected[i]], IO.bool[was[i]]]};
ProcessExtras.CheckForAbort[ ! ABORTED => EXIT ];
tester.Initialize[]; -- in case of power off/on cycle
tester.PutABDelay[0];
tester.PutAIDelay[100];
[] ← tester.PutDisables[falses];
m[i] ← TRUE;
a[i] ← b[i] ← FALSE;
e[i] ← a[i]=b[i];
[] ← tester.PutABuf[a];
[] ← tester.PutBBuf[b];
tester.Step[];
[] ← tester.CheckI[e, m ! ChipTest.CheckFailure => {Failure[expected, was]; CONTINUE}];
b[i] ← TRUE;
e[i] ← a[i]=b[i];
[] ← tester.PutABuf[a];
[] ← tester.PutBBuf[b];
tester.Step[];
[] ← tester.CheckI[e, m ! ChipTest.CheckFailure => {Failure[expected, was]; CONTINUE}];
a[i] ← TRUE;
b[i] ← FALSE;
e[i] ← a[i]=b[i];
[] ← tester.PutABuf[a];
[] ← tester.PutBBuf[b];
tester.Step[];
[] ← tester.CheckI[e, m ! ChipTest.CheckFailure => {Failure[expected, was]; CONTINUE}];
b[i] ← TRUE;
e[i] ← a[i]=b[i];
[] ← tester.PutABuf[a];
[] ← tester.PutBBuf[b];
tester.Step[];
[] ← tester.CheckI[e, m ! ChipTest.CheckFailure => {Failure[expected, was]; CONTINUE}];
m[i] ← FALSE;
cmd.out.PutF[".%d", IO.int[i]];
Process.Yield[];
ENDLOOP;
END;
Commander.Register[key: "WatchGround", proc: WatchGround, doc: "Watches for grounded pins on Dolphin IC tester"];
Commander.Register[key: "StepLoop", proc: StepLoop, doc: "Exercises Dolphin IC tester so you can watch it with a 'scope"];
Commander.Register[key: "TestTester", proc: TestTester, doc: "Ensures that tester can control and sense pins"];
END.