-- MouseTestControl.mesa
-- created by Haeberli: September 29, 1981 2:30 PM
-- added Revs 5A, 6B, 7B info, R. Garner, March 30, 1982 12:09 AM
-- ClrCnt Test Bit=0; Sim.Reset in SetVersion, R. Garner, March 31, 1982 10:11 PM
-- InitOnly added, R. Garner, April 13, 1982 2:56 PM
-- print out more info in FullTest, R. Garner, April 13, 1982 9:14 PM
-- "cycledebouncers", R. Garner, May 24, 1982 8:53 PM
-- new init pattern, R. Garner, June 2, 1982 1:33 AM
-- try new init again, R. Garner, June 7, 1982 6:29 PM
-- 16-pin pkg w/leads up, R. Garner, June 7, 1982 7:37 PM
-- try leads up again, R. Garner, June 10, 1982 10:01 PM
-- CountersZero, CountY, LookAtCounters, updated FullTest R. Garner, June 18, 1982 9:40 PM
-- Rev 8 & 9 pin maps, update square R. Garner, June 21, 1982 10:14 PM
-- TestMouseTwice R. Garner, August 2, 1982 4:08 PM
-- new legsUp Map (bad tester pins) R. Garner, August 23, 1982 8:43 PM

DIRECTORY
JaMFnsDefs,
Inline,
IODefs,
Mouse,
MouseChipImpl,
MouseSimImpl,
StreamDefs,
Tester;

MouseTestControl: PROGRAM
IMPORTS
Chip: MouseChipImpl, Inline, IODefs, JaMFnsDefs, Sim: MouseSimImpl, StreamDefs, Tester
=
{
OPEN JaMFnsDefs;

maxDebounceTest: CARDINAL = 100;

Bit: TYPE = [0..1];
Sensor: TYPE = [0..16);
Pattern: TYPE = ARRAY Sensor OF Bit;
PatIndex: TYPE = [0..30);
lastPattern: PatIndex ← 0;
currentPattern: PatIndex ← 0;

PatOrderLeftToRight: ARRAY Sensor OF Sensor = [
15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0];

PatOrderRightToLeft: ARRAY Sensor OF Sensor = [
0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15];

PatOrder: ARRAY Sensor OF Sensor ← PatOrderLeftToRight;

version: Mouse.ChipVersion ← Rev5;

oldInit: BOOLEAN ← FALSE;

legsUp: BOOLEAN ← FALSE;



TestPatterns: ARRAY PatIndex OF Pattern = [
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], [
0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0], [
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], [
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], [
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1], [
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0], [
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], [
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0]];

TestIndex: TYPE = [0..1000);
indexTest: TestIndex ← 0;
TestEntry: TYPE = RECORD [
curPat: PatIndex, sXA, sXB, sYA, sYB: Mouse.Value];
test: ARRAY TestIndex OF TestEntry;
badRes: TestEntry;
Badindex: TestIndex;

-- Local Procedures

BothSetPin: PROCEDURE [pin: Mouse.Pin, val: Mouse.Value] = {
Sim.SetPin[pin, val]; Chip.SetPin[pin, val]};

CheckResult: PROCEDURE [i: TestIndex] RETURNS [equal: BOOLEAN] = {
OPEN test[i];
badRes.sXA ← Chip.GetPin[XA];
badRes.sXB ← Chip.GetPin[XB];
badRes.sYA ← Chip.GetPin[YA];
badRes.sYB ← Chip.GetPin[YB];
equal ← (badRes.sXA = sXA) AND (badRes.sXB = sXB) AND (badRes.sYA = sYA) AND (badRes.sYB = sYB);
RETURN[equal]};

ChipSetPin: PROCEDURE [pin: Mouse.Pin, val: Mouse.Value] = {
Chip.SetPin[pin, val]};

ComparePin: PROCEDURE [pin: Mouse.Pin] RETURNS [equal: BOOLEAN] = {
equal ← Sim.GetPin[pin] = Chip.GetPin[pin]};

FullTest: PROCEDURE RETURNS [success: BOOLEAN ← TRUE] = {
lastPattern ← 0;
currentPattern ← 0;
FOR t: TestIndex IN [0..indexTest) DO
pat: PatIndex ← test[t].curPat;
Chip.PlayPat[pat];
success ← success AND CheckResult[t];
lastPattern ← currentPattern;
currentPattern ← pat;
IF NOT success THEN {Badindex ← t; EXIT}
ENDLOOP;
RETURN[success]};

MakeTestProgram: PROCEDURE = {
SaveTestEntry: PROCEDURE[i: PatIndex] = {test[indexTest] ← [curPat: i, sXA: Sim.GetPin[XA], sXB: Sim.GetPin[XB], sYA: Sim.GetPin[YA], sYB: Sim.GetPin[YB]]; indexTest ← indexTest + 1};
--Sim.Reset[];
indexTest ← 0;
SetPin ← SimSetPin;
FOR p: PatIndex IN PatIndex DO
FOR q: PatIndex IN [p..LAST[PatIndex]] DO
SetPattern[q];
SaveTestEntry[q];
SetPattern[p];
SaveTestEntry[p]
ENDLOOP;
ENDLOOP;
};

MakeTestPatterns: PROCEDURE = {
SetPin ← ChipSetPin;
FOR p: PatIndex IN PatIndex DO
Chip.RecordPat[p];
SetPattern[p];
Chip.EndRecordPat;
ENDLOOP;
};

GateTestPattern: PROCEDURE = {
SetPin[GateTest, zero];
SetPin[TestEnable, one];
SetPin[GateTest, one];
SetPin[GateTest, zero];
SetPin[TestEnable, zero];
};

GetPin: PROCEDURE [pin: Mouse.Pin] RETURNS [value: Mouse.Value] = {
RETURN[Chip.GetPin[pin]]};

Counter: PROCEDURE [a, b: Mouse.Pin] RETURNS [c: [0..4)] = {
av: INTEGER ← LOOPHOLE[GetPin[a]];
bv: INTEGER ← LOOPHOLE[GetPin[b]];
c ← Inline.BITSHIFT[av, 1] + bv;};

CountersZero: PROCEDURE RETURNS [Clear: BOOLEAN] = {
Clear ← Chip.GetPin[XA] = zero AND Chip.GetPin[XB]=zero AND Chip.GetPin[YA]=zero AND Chip.GetPin[YB]=zero;
RETURN[Clear]; };

InitializeCounters: PROCEDURE RETURNS [success: BOOLEAN] = {
OPEN IODefs;
success ← IF (version=Rev3 OR oldInit) THEN InitCntOld[]
ELSE InitCntNew[];
IF NOT success THEN {
WriteString["Counters did not initialize. Xa,Xb,Ya,Yb = "];
WriteDecimal[VtoW[Chip.GetPin[XA]]];
WriteDecimal[VtoW[Chip.GetPin[XB]]];
WriteDecimal[VtoW[Chip.GetPin[YA]]];
WriteDecimal[VtoW[Chip.GetPin[YB]]];
WriteLine[""]};
RETURN[success]};

InitCntNew: PROCEDURE RETURNS [success: BOOLEAN] = {

ShiftTestBit: PROC [bit: Bit] = {
SetPin[TestData, zero];
SetPin[TestClock, zero];
SetPin[TestData, LOOPHOLE[bit, Mouse.Value]];
SetPin[TestClock, one];
SetPin[TestClock, zero];
SetPin[TestData, zero]};

SetPin ← ChipSetPin;
SetPin[TestEnable, one];
--Load pattern 26 with clrCnt=1
FOR s: Sensor IN Sensor DO
ShiftTestBit[LOOPHOLE[TestPatterns[26][PatOrder[s]]]]; ENDLOOP;
ShiftTestBit[1]; ShiftTestBit[1];
--Gate pattern & wait a while
SetPin[GateTest, one];
FOR a: CARDINAL IN [0..1000) DO []←Counter[XA,XB]; ENDLOOP;
SetPin[GateTest, zero];
--Counters should be zero
success ← CountersZero[];
--Gate pattern 26 with clrCnt=0
Chip.PlayPat[26];
-- Apply pattern 23 (half step up and left)-correcting low-order counter bits.
Chip.PlayPat[23];
-- Apply pattern 5 (jump to 1st test vector-pattern 0).
Chip.PlayPat[5];
-- Apply pattern 0.
-- Chip.PlayPat[0];
-- Counters still zero....
success ← CountersZero[] AND success;
SetPin ← BothSetPin};

InitCntOld: PROCEDURE RETURNS [success: BOOLEAN] = {
maxInitTries: CARDINAL = 16;

HCI: TYPE = [0..4);
HCT: TYPE = ARRAY HCI OF PatIndex;

xhct: HCT = [4, 28, 11, 24];
yhct: HCT = [4, 25, 13, 29];

FakeStart: PROC = {FOR i: CARDINAL IN [0..4) DO SetPattern[4] ENDLOOP};

InitCounter: PROC [a, b: Mouse.Pin, hct: HCT]
RETURNS [success: BOOLEAN ← TRUE] = {
Chip.PlayPat[4];
Chip.PlayPat[4];
FOR l: CARDINAL IN [0..maxInitTries) DO
FOR i: HCI IN HCI DO
Chip.PlayPat[hct[i]]; IF Counter[a, b] = 3 THEN EXIT ENDLOOP;
IF Counter[a, b] = 3 THEN EXIT
REPEAT FINISHED => success ← FALSE
ENDLOOP;
Chip.PlayPat[4];
Chip.PlayPat[4];
FOR l: CARDINAL IN [0..maxInitTries) DO
FOR i: HCI IN HCI DO
Chip.PlayPat[hct[i]]; IF Counter[a, b] = 0 THEN EXIT ENDLOOP;
IF Counter[a, b] = 0 THEN EXIT
REPEAT FINISHED => success ← FALSE
ENDLOOP;
Chip.PlayPat[4];
Chip.PlayPat[4];
Chip.PlayPat[5]};

SetPin ← ChipSetPin;
SetPin[GateTest, zero];
FakeStart;
success ← InitCounter[XA, XB, xhct];
success ← InitCounter[YA, YB, yhct] AND success;
success ← CountersZero[] AND success;
SetPin ← BothSetPin};

CountX: PROCEDURE = {
HCI: TYPE = [0..4);
HCT: TYPE = ARRAY HCI OF PatIndex;
hct: HCT = [4, 28, 11, 24];

SetPin ← ChipSetPin;
SetPin[GateTest, zero];
SetPin[TestData, x];
SetPin[TestClock, x];

DO
FOR i: HCI IN HCI DO
Chip.PlayPat[hct[i]]; ENDLOOP;
IF GetJaMBreak[] THEN EXIT;
ENDLOOP;

SetPin ← BothSetPin};

CountY: PROCEDURE = {
HCI: TYPE = [0..4);
HCT: TYPE = ARRAY HCI OF PatIndex;
hct: HCT = [4, 25, 13, 29];

SetPin ← ChipSetPin;
SetPin[GateTest, zero];
SetPin[TestData, x];
SetPin[TestClock, x];

DO
FOR i: HCI IN HCI DO
Chip.PlayPat[hct[i]]; ENDLOOP;
IF GetJaMBreak[] THEN EXIT;
ENDLOOP;

SetPin ← BothSetPin};

LookAtClocks: PROCEDURE = {
SetPin ← ChipSetPin;
SetPin[TestEnable, zero];
SetPin[TestData, x];
SetPin[TestClock, x];
SetPin[RedA, x];
SetPin[RedB, x];
SetPin[YellowA, x];
SetPin[YellowB, x];
SetPin[BlueA, x];
SetPin[BlueB, x];
SetPin[GateTest, x];
DO
IF GetJaMBreak[] THEN EXIT;
ENDLOOP;
SetPin ← BothSetPin};

FlipChannel: PROCEDURE = {
chan: Tester.Channel = PopInteger[];
DO
IF GetJaMBreak[] THEN EXIT;
Tester.SetChannelValue[channel: chan, value: one];
Tester.SetChannelValue[channel: chan, value: zero];
ENDLOOP;
};

OneTestDebounce: PROCEDURE [a, b: Mouse.Pin]
RETURNS [success: BOOLEAN ← FALSE] = {
SetPin[a, x];
SetPin[b, x];
SetPin[a, zero];
SetPin[a, x];
success ← ComparePin[a] AND ComparePin[b];
SetPin[b, zero];
SetPin[b, x];
success ← ComparePin[a] AND ComparePin[b] AND success;
};

SetPattern: PROCEDURE [pat: PatIndex, gate: BOOLEAN ← TRUE] = {

-- shift one bit in test register, non-inv

ShiftTestBit: PROC [bit: Bit] = {
SetPin[TestData, zero];
SetPin[TestClock, zero];
SetPin[TestData, LOOPHOLE[bit, Mouse.Value]];
SetPin[TestClock, one];
SetPin[TestClock, zero];
SetPin[TestData, zero]};

SetPin[TestEnable, one];
SELECT version FROM
-- Inverted data for rev3, non-inverted for 5,6,7,8, 9
Rev3 => {FOR s: Sensor IN Sensor DO
ShiftTestBit[1 - TestPatterns[pat][PatOrder[s]]]; ENDLOOP;
};
Rev5, Rev5A => {FOR s: Sensor IN Sensor DO
ShiftTestBit[LOOPHOLE[TestPatterns[pat][PatOrder[s]]]]; ENDLOOP; ShiftTestBit[0];
};
Rev6A, Rev6B, Rev7A, Rev7B, Rev8, Rev9 => {FOR s: Sensor IN Sensor DO
ShiftTestBit[LOOPHOLE[TestPatterns[pat][PatOrder[s]]]]; ENDLOOP;
ShiftTestBit[1]; ShiftTestBit[0];
};
ENDCASE;

SetPin[TestEnable, zero];
IF gate THEN {
GateTestPattern[]; lastPattern ← currentPattern; currentPattern ← pat}};

SetPin: PROCEDURE [pin: Mouse.Pin, val: Mouse.Value] ← BothSetPin;

SimSetPin: PROCEDURE [pin: Mouse.Pin, val: Mouse.Value] = {
Sim.SetPin[pin, val]};

TestDebounce: PROCEDURE [color: STRING, a, b: Mouse.Pin]
RETURNS [success: BOOLEAN ← FALSE] = {
FOR i: CARDINAL IN [0..maxDebounceTest) DO
IF NOT OneTestDebounce[a, b] THEN GOTO Failed;
REPEAT Failed => {success ← FALSE}; FINISHED => {success ← TRUE};
ENDLOOP};

TestDebouncers: PROCEDURE RETURNS [success: BOOLEAN] = {
success ← TestDebounce["Red", RedA, RedB];
success ← TestDebounce["Yellow", YellowA, YellowB] AND success;
success ← TestDebounce["Blue", BlueA, BlueB] AND success};

CycleDebouncers: PROCEDURE = {
DO
IF GetJaMBreak[] THEN EXIT;
[] ← OneTestDebounce[RedA, RedB];
[] ← OneTestDebounce[YellowA, YellowB];
[] ← OneTestDebounce[BlueA, BlueB];
[] ← OneTestDebounce[BlueA, BlueB];
ENDLOOP};


-- JaM Procedures

CGP: PROCEDURE = {
pin: Mouse.Pin = LOOPHOLE[PopInteger[]];
PushInteger[LOOPHOLE[Chip.GetPin[pin]]];
};

CSP: PROCEDURE = {
val: Mouse.Value = LOOPHOLE[PopInteger[]];
pin: Mouse.Pin = LOOPHOLE[PopInteger[]];

Chip.SetPin[pin, val];
};

GetChannel: PROCEDURE = {
chan: Tester.Channel = PopInteger[];
PushInteger[LOOPHOLE[Tester.GetChannelValue[channel: chan]]];
};

GP: PROCEDURE = {
pin: Mouse.Pin = LOOPHOLE[PopInteger[]];
PushInteger[LOOPHOLE[Chip.GetPin[pin]]];
};

Mouse16Pin: PROCEDURE = {
pinMap: Mouse.PinMap = [
RedA: 98, RedB: 99, YellowA: 108, YellowB: 109, BlueA: 110, BlueB: 111,
TestEnable: 112, Gnd: 113, YA: 119, YB: 118, XA: 117, XB: 116,
TestData: 115, TestClock: 114, GateTest: 107, Vdd: 106, AnyGood: 105,
Jump: 104];
legsUpMap: Mouse.PinMap = [
RedA: 106, RedB: 107, YellowA: 114, YellowB: 115, BlueA: 116, BlueB: 117,
TestEnable: 118, Gnd: 119, YA: 113, YB: 112, XA: 111, XB: 110,
TestData: 109, TestClock: 108, GateTest: 99, Vdd: 98, AnyGood: 105,
Jump: 104];
oldlegsUpMap: Mouse.PinMap = [
RedA: 84, RedB: 85, YellowA: 86, YellowB: 87, BlueA: 88, BlueB: 89,
TestEnable: 90, Gnd: 91, YA: 83, YB: 82, XA: 81, XB: 80,
TestData: 79, TestClock: 78, GateTest: 77, Vdd: 76, AnyGood: 105,
Jump: 104];

Chip.SetPinMap[(IF legsUp THEN legsUpMap ELSE pinMap)];
SetPin[GateTest, zero];
SetPin[TestEnable, zero];
MakeTestPatterns[]};

Mouse40Pin: PROCEDURE = {
pinMap3: Mouse.PinMap = [
RedA: 3, RedB: 4, YellowA: 12, YellowB: 13, BlueA: 14, BlueB: 15,
TestEnable: 32, Gnd: 33, YA: 41, YB: 40, XA: 23, XB: 22,
TestData: 21, TestClock: 20, GateTest: 1, Vdd: 2,
AnyGood: 11, Jump: 24];

pinMap5: Mouse.PinMap = [
RedA: 7, RedB: 6, YellowA: 2, YellowB: 3, BlueA: 4, BlueB: 5,
TestEnable: 36, Gnd: 27, YA: 26, YB: 25, XA: 22, XB: 21,
TestData: 20, TestClock: 11, GateTest: 9, Vdd: 8,
AnyGood: 10, Jump: 23];

pinMap5A: Mouse.PinMap = [
RedA: 3, RedB: 4, YellowA: 12, YellowB: 13, BlueA: 14, BlueB: 15,
TestEnable: 17, Gnd: 18, YA: 19, YB: 28, XA: 10, XB: 9,
TestData: 8, TestClock: 7, GateTest: 1, Vdd: 2,
AnyGood: 6, Jump: 11];

pinMap7A: Mouse.PinMap = [
RedA: 5, RedB: 6, YellowA: 27, YellowB: 28, BlueA: 29, BlueB: 30,
TestEnable: 32, Gnd: 33, YA: 34, YB: 35, XA: 37, XB: 38,
TestData: 39, TestClock: 40, GateTest: 3, Vdd: 4,
AnyGood: 2, Jump: 36];

pinMap7B: Mouse.PinMap = [
RedA: 33, RedB: 34, YellowA: 16, YellowB: 17, BlueA: 18, BlueB: 19,
TestEnable: 21, Gnd: 22, YA: 23, YB: 24, XA: 26, XB: 27,
TestData: 28, TestClock: 29, GateTest: 31, Vdd: 32,
AnyGood: 30, Jump: 25];

pinMap8: Mouse.PinMap = [
RedA: 5, RedB: 6, YellowA: 27, YellowB: 28, BlueA: 29, BlueB: 30,
TestEnable: 32, Gnd: 33, YA: 34, YB: 35, XA: 37, XB: 38,
TestData: 39, TestClock: 40, GateTest: 3, Vdd: 4,
AnyGood: 2, Jump: 36];

pinMap9: Mouse.PinMap = [
RedA: 13, RedB: 14, YellowA: 16, YellowB: 17, BlueA: 18, BlueB: 19,
TestEnable: 29, Gnd: 30, YA: 31, YB: 32, XA: 41, XB: 40,
TestData: 39, TestClock: 37, GateTest: 5, Vdd: 12,
AnyGood: 37, Jump: 33];

Chip.SetPinMap[(SELECT version FROM
Rev3 => pinMap3, Rev5 => pinMap5, Rev5A => pinMap5A,
Rev7A => pinMap7A, Rev7B => pinMap7B,
Rev8 => pinMap8, Rev9 => pinMap9,
ENDCASE => pinMap3)];

SetPin[GateTest, zero];
SetPin[TestEnable, zero];
MakeTestPatterns[]};

MouseProbeCard: PROCEDURE = {
pinMap3: Mouse.PinMap = [
RedA: 38, RedB: 39, YellowA: 59, YellowB: 69, BlueA: 61, BlueB: 60,
TestEnable: 33, Gnd: 31, YA: 29, YB: 19, XA: 1, XB: 0, TestData: 6,
TestClock: 8, GateTest: 27, Vdd: 37, AnyGood: 10, Jump: 3];

newPinMap: Mouse.PinMap = [
RedA: 61, RedB: 51, YellowA: 33, YellowB: 31, BlueA: 29, BlueB: 19,
TestEnable: 3, Gnd: 0, YA: 6, YB: 9, XA: 27, XB: 37, TestData: 38,
TestClock: 39, GateTest: 57, Vdd: 68, AnyGood: 41, Jump: 25];

IF version <= Rev3 THEN Chip.SetPinMap[pinMap3] ELSE Chip.SetPinMap[newPinMap] ;
SetPin[GateTest, zero];
SetPin[TestEnable, zero];
MakeTestPatterns[]};

Reset: PROCEDURE = {
Tester.Reset;
Chip.Reset;
Sim.Reset;
MakeTestProgram;
MouseProbeCard;
SetPin ← BothSetPin};

JaMSetPattern: PROCEDURE = {
patIndex: PatIndex = LOOPHOLE[PopInteger[]];
SetPin ← ChipSetPin;
SetPattern[patIndex];
SetPin ← BothSetPin};

JaMSetPatternNG: PROCEDURE = {
patIndex: PatIndex = LOOPHOLE[PopInteger[]];
SetPin ← ChipSetPin;
SetPattern[patIndex, FALSE];
SetPin ← BothSetPin};

SetChannel: PROCEDURE = {
val: Tester.Value = LOOPHOLE[PopInteger[]];
chan: Tester.Channel = PopInteger[];

Tester.SetChannelValue[channel: chan, value: val];
};

SetVersions: PROCEDURE [v: Mouse.ChipVersion] = {
Sim.SetVersion[v];
Chip.SetVersion[v];
version ← v;
PatOrder ← IF v = Rev3 THEN PatOrderLeftToRight ELSE PatOrderRightToLeft;
IODefs.WriteLine["Welcome to the ’Mus opticus’ test!"];
MakeTestProgram;
};

SetVersion: PROCEDURE = {
v: Mouse.ChipVersion = LOOPHOLE[PopInteger[]];
legsUp ← PopInteger[] # 0;
SetVersions[v]};

SetOldInit: PROCEDURE = {
oldInit ← PopInteger[] # 0};

SGP: PROCEDURE = {
pin: Mouse.Pin = LOOPHOLE[PopInteger[]];
PushInteger[LOOPHOLE[Sim.GetPin[pin]]];
};

SP: PROCEDURE = {
val: Mouse.Value = LOOPHOLE[PopInteger[]];
pin: Mouse.Pin = LOOPHOLE[PopInteger[]];
Chip.SetPin[pin, val];
};

Square: PROCEDURE = {
cycles: INTEGER = PopInteger[];
chan: Tester.Channel = PopInteger[];

FOR i: INTEGER IN [0..cycles) DO
Tester.SetChannelValue[channel: chan, value: one];
Tester.SetChannelValue[channel: chan, value: zero];
ENDLOOP;
};

SSP: PROCEDURE = {
val: Mouse.Value = LOOPHOLE[PopInteger[]];
pin: Mouse.Pin = LOOPHOLE[PopInteger[]];

Sim.SetPin[pin, val];
};

TestAMouse: PROCEDURE = {
OPEN IODefs;
status: INTEGER ← 0;
WriteLine["squeak !"];
Sim.Reset[];

IF TestDebouncers[] THEN WriteLine["Mouse can bounce!"]
ELSE { WriteLine["squeal ! Debouncer test failed"]; status ← 1};
IF InitializeCounters[] THEN {
IF NOT CountersZero[] THEN WriteString["Counters no longer zero!"]
ELSE
IF FullTest[] THEN WriteLine["Mouse is Good!"]
ELSE {
WriteString["squawk! Initialized OK, but full test failed from: "];
WriteDecimal[lastPattern];
WriteString[" to: "];
WriteDecimal[currentPattern];
WriteLine[""];
WriteString["Xa,Xb,Ya,Yb was "];
WriteDecimal[VtoW[badRes.sXA]]; WriteDecimal[VtoW[badRes.sXB]];
WriteDecimal[VtoW[badRes.sYA]]; WriteDecimal[VtoW[badRes.sYB]];
WriteLine[""];
WriteString["Xa,Xb,Ya,Yb is "];
WriteDecimal[VtoW[Chip.GetPin[XA]]];
WriteDecimal[VtoW[Chip.GetPin[XB]]];
WriteDecimal[VtoW[Chip.GetPin[YA]]];
WriteDecimal[VtoW[Chip.GetPin[YB]]];
WriteLine[""];
WriteString["should be "];
WriteDecimal[VtoW[test[Badindex].sXA]];
WriteDecimal[VtoW[test[Badindex].sXB]];
WriteDecimal[VtoW[test[Badindex].sYA]];
WriteDecimal[VtoW[test[Badindex].sYB]];
WriteLine[""];
status ← status + 2 + (8 * currentPattern) + (30 * 8 * lastPattern)}}
ELSE {status ← status + 4 };
PushInteger[status];
};

TestMouseTwice: PROCEDURE = BEGIN
OPEN IODefs;
status: INTEGER ← 0;
Sim.Reset[];

IF TestDebouncers[] THEN WriteLine["Mouse can bounce!"]
ELSE WriteLine["Debouncer test failed"];
IF InitializeCounters[] AND FullTest[] THEN WriteLine["Mouse is good once!"]
ELSE WriteLine["Not even a good one nighter!"];
IF InitializeCounters[] AND FullTest[] THEN WriteLine["and good twice"]
ELSE WriteLine["Screech! Failed second time !"];
END;

InitOnly: PROCEDURE = BEGIN
OPEN IODefs;
IF InitializeCounters[] THEN WriteString["InitOK"] ELSE WriteString["Init Fail"];
END;

VtoW: PROCEDURE [val: Mouse.Value] RETURNS [w: WORD] = BEGIN
RETURN[Inline.BITAND[LOOPHOLE[val, WORD], 1]];
END;


WriteTestPattern: PROCEDURE = {
OPEN IODefs;
dh: StreamDefs.DiskHandle = StreamDefs.NewByteStream[name: "MouseTestPatterns.txt", access: StreamDefs.WriteAppend];
oh: StreamDefs.StreamHandle = GetOutputStream[];
dh.reset[dh];
SetOutputStream[dh];

WriteLine[""];
FOR t: TestIndex IN [0..indexTest) DO
pat: PatIndex ← test[t].curPat;
WriteDecimal[pat]; WriteString[", "];
WriteDecimal[Inline.BITAND[LOOPHOLE[test[t].sXA, WORD], 1]];
WriteDecimal[Inline.BITAND[LOOPHOLE[test[t].sXB, WORD], 1]];
WriteDecimal[Inline.BITAND[LOOPHOLE[test[t].sYA, WORD], 1]];
WriteDecimal[Inline.BITAND[LOOPHOLE[test[t].sYB, WORD], 1]];
WriteString[", "];
WriteLine[""];
ENDLOOP;
WriteLine[""];

SetOutputStream[oh];
dh.destroy[dh];
};

{
Register["cgp", CGP];
Register["countx", CountX];
Register["county", CountY];
Register["cd", CycleDebouncers];
Register["lac", LookAtClocks];
Register["fc", FlipChannel];
Register["csp", CSP];
Register["getchan", GetChannel];
Register["gp", GP];
Register["m16", Mouse16Pin];
Register["m40", Mouse40Pin];
Register["mp", MouseProbeCard];
Register["reset", Reset];
Register["setchan", SetChannel];
Register["sc", SetChannel];
Register["setpattern", JaMSetPattern];
Register["sv", SetVersion];
Register["soi", SetOldInit];
Register["sgp", SGP];
Register["sp", SP];
Register["spng", JaMSetPatternNG];
Register["square", Square];
Register["testamouse", TestAMouse];
Register["mm", TestMouseTwice];
Register["init", InitOnly];
Register["writetestpattern", WriteTestPattern];

Reset;
};

}.