-- JaMMOSSIMFnsImplB.mesa
-- created by Haeberli from JamMOSSIM.mesa:  7-Jan-82 13:17:11

DIRECTORY
  InlineDefs,
  JaMFnsDefs,
  JaMMOSSIMFns,
  Mopcodes,
  MOSSIMFns,
  StreamDefs,
  StringDefs;

JaMMOSSIMFnsImplB: PROGRAM
  IMPORTS InlineDefs, JaMFnsDefs, JaMMOSSIMFns, MOSSIMFns
  EXPORTS JaMMOSSIMFns =
  {
  OPEN InlineDefs, JaMFnsDefs, JaMMOSSIMFns, MOSSIMFns, StreamDefs;


  --vector of channel commands for the tester A channels
  --In OutA and Enable, bit 0 means send this group of 8 bits at the next step
  OutA: ARRAY [0..15] OF WORD;

  --vector of channel commands for the tester Enable channels.  Initialized
  --to Disabled (0).
  Enable: ARRAY [0..15] OF WORD;

  --array of bits, one per channel, containing the channels to be inspected
  --after the next step.
  Look: ARRAY [0..7] OF WORD;

  --array of bits containing the expected values for the channels in Look.
  --The tester does: "if (Result xor Expected) and Look # 0 then error"
  Expected: ARRAY [0..7] OF WORD;


  s: StreamDefs.StreamHandle;  --output stream for vectors


  CheckFirstBlock, CheckSecondBlock: BOOLEAN;  --indicates that
  --some value in the block was examined, so tester
  --must do a read/compare before doing the next step.

  DoStep: BOOLEAN ← FALSE;  --have changed some edge pin input, so do a step
  --modified at least one edge pin (as opposed to internal nodes).

  StepControl: TYPE = CARDINAL [0..15];
  Steps: LONG DESCRIPTOR FOR PACKED ARRAY OF StepControl;
  Data: LONG DESCRIPTOR FOR ARRAY OF WORD;
  StepCount: CARDINAL;
  DataCount: CARDINAL;


  --Read the file into core.  Takes a stream from JaM, returns number
  --of steps loaded
  LoadTest: PUBLIC PROC = {
    item: WORD;
    BlockCount: CARDINAL ← 0;  --count of words sent in the current block
    NopInst: CARDINAL = 0;
    k: CARDINAL;

    Steps ← DESCRIPTOR[1000000B, 2000B];  --first 1k of bank 4
    Data ← DESCRIPTOR[1002000B, 176000B];  --rest of bank 4 
    s ← PopStream[];
    StepCount ← 0;
    DataCount ← 8;  --skip temp buffer

    UNTIL s.endof[s] DO
      item ← s.get[s];
      IF BITAND[item, 100000B] # 0 THEN  --block done
        {
        --fill out block to 4 or 8 words (with nops)
        UNTIL ((BlockCount > 0) AND ((BlockCount MOD 4) = 0)) DO
          Data[DataCount] ← NopInst;
          DataCount ← DataCount + 1;
          BlockCount ← BlockCount + 1;
          ENDLOOP;
        --set the GO bit in the last word
        Data[DataCount - 1] ← BITOR[Data[DataCount - 1], 100000B];

        --In bad cases, we can have as many as 12 4-word blocks.  Since the tester
        --can only do 1 to 4 blocks per step, we may have to do multiple steps.
        UNTIL BlockCount <= 16 DO
          Steps[StepCount] ← 14B;  --tells the tester to send 4 blocks, no read
          StepCount ← StepCount + 1;
          BlockCount ← BlockCount - 16;
          ENDLOOP;

        --Check for read after step
        IF BITAND[item, 1] # 0 THEN  --want to read/check the first block
          {
          FOR k IN [0..7] DO
            Data[DataCount] ← s.get[s]; DataCount ← DataCount + 1; ENDLOOP;
          BlockCount ← BlockCount + 1;
          };

        IF BITAND[item, 2] # 0 THEN  --want to read/check the second block
          {
          FOR k IN [0..7] DO
            Data[DataCount] ← s.get[s]; DataCount ← DataCount + 1; ENDLOOP;
          BlockCount ← BlockCount + 2;
          };

        BlockCount ← BlockCount - 4;  --since it is biased
        Steps[StepCount] ← LOOPHOLE[BlockCount, StepControl];
        StepCount ← StepCount + 1;
        BlockCount ← 0;
        }
      ELSE {
        Data[DataCount] ← item;
        DataCount ← DataCount + 1;
        BlockCount ← BlockCount + 1;
        };

      ENDLOOP;
    PushInteger[LOOPHOLE[StepCount, INTEGER]];  --return the number of steps
    };


  DoTest: PROC [c: INTEGER, control, data: LONG POINTER] RETURNS [cc: INTEGER] =
    MACHINE CODE {Mopcodes.zMISC, 14B};

  DoOutput: PROC [data, addr: WORD] = MACHINE CODE {Mopcodes.zMISC, 6B};

  DoInput: PROC [addr: INTEGER] RETURNS [data: INTEGER] = MACHINE CODE {
    Mopcodes.zMISC, 5B};

  --Do Output from JaM
  Out: PUBLIC PROC = {
    addr, data: INTEGER;
    addr ← PopInteger[];
    data ← PopInteger[];
    DoOutput[data, addr];
    };

  --Do Input from Jam
  In: PUBLIC PROC = {
    addr, data: INTEGER;
    addr ← PopInteger[];
    data ← DoInput[addr];
    PushInteger[data];
    };

  --Set up fixed tester registers
  SetUpTester: PUBLIC PROC = {
    e: ARRAY [0..14] OF INTEGER ← [
      20377B, 20777B, 21377B, 21777B, 22377B, 22777B, 23377B, 23777B, 24377B,
      24777B, 25377B, 25777B, 26377B, 26777B, 27377B];

    a: ARRAY [0..14] OF INTEGER ← [
      40000B, 40400B, 41000B, 41400B, 42000B, 42400B, 43000B, 43400B, 44000B,
      44400B, 45000B, 45400B, 46000B, 46400B, 47000B];

    b: ARRAY [0..14] OF INTEGER ← [
      60377B, 60777B, 61377B, 61777B, 62377B, 62777B, 63377B, 63777B, 64377B,
      64777B, 65377B, 65777B, 66377B, 66777B, 67377B];

    i: CARDINAL;

    DoOutput[1, 0];  --release reset
    DoOutput[2000B, 1];  --input group select buffer ← 0
    DoOutput[4020B, 1];  --clock parameter 1
    DoOutput[10777B, 1];  --clock parameter 2
    FOR i IN [0..14] DO
      DoOutput[a[i], 1];  --A channels ← 0 
      DoOutput[b[i], 1];  --B channels ← 1 
      DoOutput[e[i], 1];  --Enable channels ← 1 (open) 
      ENDLOOP;
    DoOutput[100000B, 1];  --Do one step
    };


  --Run a test.  Takes a step count and returns final step count
  RunTest: PUBLIC PROC = {
    InCount, OutCount: INTEGER;
    StepAddr: LONG POINTER = LOOPHOLE[1000000B, LONG POINTER];
    DataAddr: LONG POINTER = LOOPHOLE[1002000B, LONG POINTER];
    i: CARDINAL;

    InCount ← PopInteger[];
    OutCount ← DoTest[InCount, StepAddr, DataAddr];
    PushInteger[OutCount];  --return final step
    FOR i IN [0..7] DO
      PushInteger[LOOPHOLE[(LOOPHOLE[1002000B + i, LONG POINTER])↑, INTEGER]];
      ENDLOOP;
    };


  CheckTest: PUBLIC PROC = {
    s: StreamDefs.StreamHandle;
    i: CARDINAL;
    sc: StepControl;
    wc: CARDINAL;
    dc: CARDINAL ← 8;  --data blocks begin at word 8

    s ← PopStream[];
    FOR i IN [0..StepCount - 1] DO
      sc ← Steps[i];
      --form word count
      wc ← 4 + BITAND[sc, 14B] + ((BITAND[sc, 1]) + (BITAND[sc, 2]/2))*8;
      s.put[s, sc];
      UNTIL wc = 0 DO s.put[s, Data[dc]]; dc ← dc + 1; wc ← wc - 1; ENDLOOP;
      ENDLOOP;
    };


  --Tinit takes the output stream from Jam, and initializes the tester tables.
  Tinit: PUBLIC PROC = {

    i: CARDINAL;

    s ← PopStream[];

    OutA ← [
      40000B, 40400B, 41000B, 41400B, 42000B, 42400B, 43000B, 43400B, 44000B,
      44400B, 45000B, 45400B, 46000B, 46400B, 47000B, 47400B];

    Enable ← [
      20000B, 20400B, 21000B, 21400B, 22000B, 22400B, 23000B, 23400B, 24000B,
      24400B, 25000B, 25400B, 26000B, 26400B, 27000B, 27400B];

    FOR i IN [0..7] DO Look[i] ← 0; Expected[i] ← 0; ENDLOOP;
    CheckFirstBlock ← FALSE;
    CheckSecondBlock ← FALSE;
    DoStep ← FALSE;
    };

  --use THi instead of hi when sending data to the tester.  Takes a channel
  --number and a name.  Sends to the simulator and tester.
  THi: PUBLIC PROC = {
    ch, m, i: INTEGER;
    ch ← PopInteger[];
    i ← ch/8;
    m ← BITSHIFT[200B, -BITAND[ch, 7]];
    IF BITAND[Enable[i], m] = 0 THEN  --if not enabled 
      {
      Enable[i] ← BITOR[Enable[i], BITOR[100000B, m]];  --set the enable
      OutA[i] ← BITOR[OutA[i], BITOR[100000B, m]];  --set the bit
      }
    ELSE  --if not equal to current value
      IF BITAND[OutA[i], m] # m THEN OutA[i] ← BITOR[OutA[i], BITOR[100000B, m]];
    SetInputHigh[];
    };

  --use TLo instead of lo when sending data to the tester.  Takes a channel
  --number and a name.  Sends to the simulator and tester.
  TLo: PUBLIC PROC = {
    ch, m, i: INTEGER;
    ch ← PopInteger[];
    i ← ch/8;
    m ← BITSHIFT[200B, -BITAND[ch, 7]];
    IF BITAND[Enable[i], m] = 0 THEN  --if not enabled
      {
      Enable[i] ← BITOR[Enable[i], BITOR[100000B, m]];  --set the enable
      OutA[i] ← BITOR[BITAND[BITNOT[m], OutA[i]], 100000B];  --clear the bit
      }
    ELSE  --if not equal to current value
      IF BITAND[OutA[i], m] # 0 THEN
        OutA[i] ← BITOR[BITAND[BITNOT[m], OutA[i]], 100000B];  --clear the bit
    SetInputLow[];
    };

  --use Tx instead of x when sending data to the tester.  Takes a channel
  --number and a name.  Sends to the simulator and tester.
  Tx: PUBLIC PROC = {
    ch, m, i: INTEGER;
    ch ← PopInteger[];
    i ← ch/8;
    m ← BITSHIFT[200B, -BITAND[ch, 7]];
    IF BITAND[Enable[i], m] # 0 THEN  --if enabled
      Enable[i] ← BITOR[BITAND[BITNOT[m], Enable[i]], 100000B];  --clear the enable
    SetInputX[];
    };

  --Gnv1 takes a channel number and puts the channel into the read vectors.
  --The comparison is done with the data provided by the simulator.
  Gnv1: PUBLIC PROC = {
    value: INTEGER;
    ch: INTEGER ← PopInteger[];
    i: INTEGER ← ch/16;
    m: INTEGER ← BITSHIFT[100000B, -BITAND[ch, 17B]];
    IF i < 4 THEN CheckFirstBlock ← TRUE ELSE CheckSecondBlock ← TRUE;
    targv[1].length ← 0;
    PopString[targv[1]];
    targc ← 2;
    value ← getNodeValue[];
    Look[i] ← BITOR[Look[i], m];
    Expected[i] ←
      (IF value = 0 THEN (BITAND[Expected[i], BITNOT[m]])
       ELSE (BITOR[Expected[i], m]));
    PushInteger[value];
    };

  --Tstep does one step and outputs commands for changed channels to the
  --tester.  It is called by the Jam program after all values generated by
  --the previous step (if any) have been examined,
  --and after all input values for this
  --step have been set up.  We output the step command for the previous tester
  --cycle at this time, with the Read bit ON if any values were examined.
  --Then we output Look and Expected if any values were read, then we output the
  --Input vectors for the next step, and STEP the simulator.
  Tstep: PUBLIC PROC = {
    nout: CARDINAL ← 0;
    i: INTEGER;
    control: WORD ← 100000B;

    --put out the step command for previous data (if some input connected to a pin has been changed
    IF DoStep THEN {
      IF CheckFirstBlock THEN control ← control + 1;
      IF CheckSecondBlock THEN control ← control + 2;
      s.put[s, control];

      IF CheckFirstBlock THEN {
        FOR i IN [0..3] DO s.put[s, Expected[i]]; ENDLOOP;
        FOR i IN [0..3] DO s.put[s, Look[i]]; Look[i] ← 0; ENDLOOP;
        CheckFirstBlock ← FALSE;
        };

      IF CheckSecondBlock THEN {
        FOR i IN [4..7] DO s.put[s, Expected[i]]; ENDLOOP;
        FOR i IN [4..7] DO s.put[s, Look[i]]; Look[i] ← 0; ENDLOOP;
        CheckSecondBlock ← FALSE;
        };
      };

    --send any inputs that will change in preparation for the next step
    FOR i IN [0..15] DO
      IF BITAND[OutA[i], 100000B] # 0 THEN {
        OutA[i] ← BITAND[OutA[i], 77777B]; s.put[s, OutA[i]]; nout ← nout + 1; };

      IF BITAND[Enable[i], 100000B] # 0 THEN {
        Enable[i] ← BITAND[Enable[i], 77777B];
        s.put[s, BITXOR[Enable[i], 377B]];  --enables are inverted at the tester 
        nout ← nout + 1;
        };
      ENDLOOP;

    DoStep ← TRUE;
    Step[];  --step the simulator
    };

  -- New procedures to allow immediate manipulation of tester, if present.

  --Set up tester without changing state
  SetUpIntact: PUBLIC PROC = {
    DoOutput[2000B, 1];  --input group select buffer ← 0
    DoOutput[4020B, 1];  --clock parameter 1
    DoOutput[10777B, 1];  --clock parameter 2
    DoOutput[100000B, 1];  --Do one step
    };


  --Read the state of the tester quickly, without a test vector
  ReadState: PUBLIC PROC = {

    i: CARDINAL;

    DoOutput[2000B, 1];  --input group select buffer ← 0
    DoOutput[4020B, 1];  --clock parameter 1
    DoOutput[10777B, 1];  --clock parameter 2
    DoOutput[100000B, 1];  --Do one step
    PushInteger[0];  --return final step
    FOR i IN [0..7] DO PushInteger[DoInput[1]]; ENDLOOP;
    };


  --Read the state of a single tester channel
  ReadChan: PUBLIC PROC = {

    chan, binaryState: INTEGER;
    w, b, i: CARDINAL;
    state: ARRAY [0..7] OF WORD;

    chan ← PopInteger[];
    w ← chan/16;
    b ← (chan MOD 16) - 15;
    DoOutput[2000B, 1];  --input group select buffer ← 0
    DoOutput[4020B, 1];  --clock parameter 1
    DoOutput[10777B, 1];  --clock parameter 2
    DoOutput[100000B, 1];  --Do one step
    FOR i IN [0..7] DO state[i] ← DoInput[1]; ENDLOOP;
    binaryState ← BITAND[BITSHIFT[state[w], b], 1];
    PushInteger[binaryState];
    };


  --Set the state of a single tester channel
  SetChan: PUBLIC PROC = {

    chan, newState: INTEGER;
    grp, w, b, i: CARDINAL;
    data: WORD;
    state: ARRAY [0..7] OF WORD;

    chan ← PopInteger[];
    newState ← BITAND[PopInteger[], 1];
    w ← chan/16;
    grp ← chan/8;
    b ← 7 - (chan MOD 8);
    DoOutput[2000B, 1];  --input group select buffer ← 0
    DoOutput[4020B, 1];  --clock parameter 1
    DoOutput[10777B, 1];  --clock parameter 2
    DoOutput[100000B, 1];  --Do one step
    FOR i IN [0..7] DO state[i] ← DoInput[1]; ENDLOOP;
    data ← state[w];
    IF BITAND[grp, 1] = 0 THEN data ← BITSHIFT[data, -8]
    ELSE data ← BITAND[data, 377B];
    data ← BITOR[BITAND[data, BITNOT[BITSHIFT[1, b]]], BITSHIFT[newState, b]];
    DoOutput[40000B + BITSHIFT[grp, 8] + data, 1];  --set output
    DoOutput[100000B, 1];  --Do one step
    };
  }.