-- MouseVerifyControl.mesa
-- created by Haeberli: 23-Dec-81 13:00:45

DIRECTORY
  JaMFnsDefs,
  InlineDefs,
  IODefs,
  Mouse,
  MouseMossimImpl,
  MouseSimImpl;

MouseVerifyControl: PROGRAM
  IMPORTS Chip: MouseMossimImpl, InlineDefs, IODefs, JaMFnsDefs, Sim: MouseSimImpl
  =
  {
  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 ← Rev3;


  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];

  -- Local Procedures

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

  CheckResult: PROCEDURE RETURNS [equal: BOOLEAN] = {
    equal ← (ComparePin[XA]) AND (ComparePin[XB]) AND (ComparePin[YA])
      AND (ComparePin[YB]);
    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] = {
    SetPin ← BothSetPin;
    FOR p: PatIndex IN PatIndex DO
      FOR q: PatIndex IN [p..LAST[PatIndex]] DO
        SetPattern[q];
        success ← success AND CheckResult[];
        IF NOT success THEN EXIT;
        SetPattern[p];
        success ← success AND CheckResult[];
        IF NOT success THEN EXIT
        ENDLOOP;
      IF NOT success THEN EXIT;
      ENDLOOP;
    RETURN[success]};

  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]]};

  InitializeCounters: 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];

    Counter: PROC [a, b: Mouse.Pin] RETURNS [c: [0..4)] = {
      av: INTEGER ← LOOPHOLE[GetPin[a]];
      bv: INTEGER ← LOOPHOLE[GetPin[b]];
      c ← InlineDefs.BITSHIFT[av, 1] + bv;
      };
    InitAll: PROC = {FOR i: CARDINAL IN [0..4) DO SetPattern[4] ENDLOOP};
    InitCounter: PROC [a, b: Mouse.Pin, hct: HCT]
      RETURNS [success: BOOLEAN ← TRUE] = {
      SetPattern[4];
      SetPattern[4];
      FOR l: CARDINAL IN [0..maxInitTries) DO
        FOR i: HCI IN HCI DO
          SetPattern[hct[i]]; IF Counter[a, b] = 3 THEN EXIT ENDLOOP;
        IF Counter[a, b] = 3 THEN EXIT
        REPEAT FINISHED => success ← FALSE
        ENDLOOP;
      SetPattern[4];
      SetPattern[4];
      FOR l: CARDINAL IN [0..maxInitTries) DO
        FOR i: HCI IN HCI DO
          SetPattern[hct[i]]; IF Counter[a, b] = 0 THEN EXIT ENDLOOP;
        IF Counter[a, b] = 0 THEN EXIT
        REPEAT FINISHED => success ← FALSE
        ENDLOOP;
      SetPattern[4];
      SetPattern[4];
      SetPattern[5]};

    SetPin ← ChipSetPin;

    SetPin[GateTest, zero];
    InitAll;
    success ← InitCounter[XA, XB, xhct];
    success ← InitCounter[YA, YB, yhct] AND success;
    success ← (Counter[XA, XB] = 0) AND (Counter[YA, YB] = 0) AND success;
    SetPin ← BothSetPin};

  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] = {
    ShiftTestBit: PROC [bit: Bit] = {
      SetPin[TestData, zero];
      SetPin[TestClock, zero];
      SetPin[TestData, LOOPHOLE[1 - bit, Mouse.Value]];
      SetPin[TestClock, one];
      SetPin[TestClock, zero];
      SetPin[TestData, zero]};

    SetPin[TestEnable, one];
    SELECT version FROM
      Rev3 => {FOR s: Sensor IN Sensor DO
        ShiftTestBit[TestPatterns[pat][PatOrder[s]]]; ENDLOOP;
};
      Rev4, Rev5 => {FOR s: Sensor IN Sensor DO
        ShiftTestBit[LOOPHOLE[1 - TestPatterns[pat][PatOrder[s]]]]; ENDLOOP;
      ShiftTestBit[1];
};
      Rev6, Rev7 => {FOR s: Sensor IN Sensor DO
        ShiftTestBit[LOOPHOLE[1 - TestPatterns[pat][PatOrder[s]]]]; ENDLOOP;
      ShiftTestBit[1]; ShiftTestBit[1];
};
      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};


  -- 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];
    };

  Mouse16Pin: PROCEDURE = {
    pinMap: Mouse.PinMap = [
      RedA: 98, RedB: 99, YellowA: 108, YellowB: 109, BlueA: 110, BlueB: 111,
      TestEnable: 112, Gnd: 114, YA: 119, YB: 118, XA: 117, XB: 116,
      TestData: 115, TestClock: 114, GateTest: 107, Vdd: 106, AnyGood: 105,
      Jump: 104];

    Chip.SetPinMap[pinMap]};

  Mouse40Pin: PROCEDURE = {
    pinMap: 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];

    Chip.SetPinMap[pinMap]};

  MouseProbeCard: PROCEDURE = {
    pinMap: 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];

    Chip.SetPinMap[pinMap]};

  Reset: PROCEDURE = {Chip.Reset; Sim.Reset; 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};

  SetVersions: PROCEDURE [v: Mouse.ChipVersion] = {
    Sim.SetVersion[v];
    Chip.SetVersion[v];
    version ← v;
    PatOrder ← IF v = Rev3 THEN PatOrderLeftToRight ELSE PatOrderRightToLeft};

  SetVersion: PROCEDURE = {
    version: Mouse.ChipVersion = LOOPHOLE[PopInteger[]];
    SetVersions[version]};

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

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

    Sim.SetPin[pin, val];
    };

  TestAMouse: PROCEDURE = {
    OPEN IODefs;

    status: INTEGER ← 0;
    Sim.Reset;

    IF TestDebouncers[] THEN WriteLine["Debouncers Tested OK"]
    ELSE {WriteLine["Debouncer test failed"]; status ← 1};
    IF InitializeCounters[] THEN {
      IF FullTest[] THEN WriteLine["Mouse is Good!"]
      ELSE {
        WriteString["Initialized OK, full test failed at step from: "];
        WriteDecimal[lastPattern];
        WriteString["  to: "];
        WriteDecimal[currentPattern];
        WriteLine[""];
        status ← status + 2 + (8*currentPattern) + (30*8*lastPattern)}}
    ELSE {WriteLine["Unable to initialize counters"]; status ← status + 4};
    PushInteger[status];
    };

  {
  Register["cgp", CGP];
  Register["csp", CSP];
  Register["mouse16pin", Mouse16Pin];
  Register["mouse40pin", Mouse40Pin];
  Register["mouseprobecard", MouseProbeCard];
  Register["reset", Reset];
  Register["setpattern", JaMSetPattern];
  Register["spng", JaMSetPatternNG];
  Register["setversion", SetVersion];
  Register["sgp", SGP];
  Register["ssp", SSP];
  Register["testamouse", TestAMouse];

  Reset;
  };

  }.