-- Copyright (C) 1984  by Xerox Corporation. All rights reserved. 
-- TestFlukeServer.mesa, HGM,  8-Jan-84  4:41:19

DIRECTORY
  FormSW USING [
    AllocateItemDescriptor, ClientItemsProcType, CommandItem, newLine, ProcType, StringItem],
  Inline USING [BITAND, BytePair, HighByte, LowByte],
  Put USING [Char, CR, Line, LongDecimal, LongNumber, Number, Text],
  Runtime USING [GetBcdTime],
  String USING [AppendString],
  System USING [GetClockPulses, Microseconds, Pulses, PulsesToMicroseconds],
  Time USING [Append, Unpack],
  Tool USING [Create, MakeSWsProc, MakeFormSW, MakeFileSW, UnusedLogName],
  ToolWindow USING [TransitionProcType],
  UserInput USING [UserAbort],
  Window USING [Handle],

  MesaRPC USING [CallFailed, ImportFailed],
  Multibus USING [IOAddress, Input, Output, RawRead],
  MultibusRpcControl USING [ImportInterface, UnimportInterface],
  MultibusAddresses USING [eprom, IOAddress, timeout];

TestFlukeServer: PROGRAM
  IMPORTS
    FormSW, Inline, Put, Runtime, String, System, Time, Tool, UserInput,
    MesaRPC, Multibus, MultibusRpcControl =
  BEGIN

  target: LONG STRING ← NIL;

  Echo: FormSW.ProcType =
    BEGIN
    start, end: System.Pulses;
    cycles: LONG CARDINAL ← 0;
    ms: LONG CARDINAL;
    noBind: BOOLEAN ← FALSE;
    harmless: Multibus.IOAddress ← LOOPHOLE[69000H]; -- DES Chip
    start ← System.GetClockPulses[];
    MultibusRpcControl.ImportInterface[[NIL, target] !
      MesaRPC.ImportFailed =>
        BEGIN
	noBind ← TRUE;
	Put.Text[log, "Import from "L];
	Put.Text[log, target];
	Put.Text[log, " failed: "L];
	SELECT why FROM
	  communications => Put.Text[log, "communications"L];
	  badInstance => Put.Text[log, "badInstance"L];
	  badVersion => Put.Text[log, "badVersion"L];
	  wrongVersion => Put.Text[log, "wrongVersion"L];
	  unbound => Put.Text[log, "unbound"L];
	  stubProtocol => Put.Text[log, "stubProtocol"L];
	  ENDCASE => Put.Text[log, "??"L];
	Put.Line[log, "."L];
	CONTINUE;
	END];
    IF noBind THEN RETURN;
    end ← System.GetClockPulses[];
    ms ← System.PulsesToMicroseconds[[end-start]]/1000;
    Put.Text[log, "It took "L];
    Put.LongDecimal[log, ms];
    Put.Line[log, " ms to Import Multibus."L];
    start ← System.GetClockPulses[];
    FOR i: CARDINAL IN [0..1000) DO
      [] ← Multibus.Input[harmless];
      Multibus.Output[0, harmless];
      cycles ← cycles + 1;
      ENDLOOP;
    end ← System.GetClockPulses[];
    ms ← System.PulsesToMicroseconds[[end-start]]/1000;
    Put.Text[log, "It took "L];
    Put.LongDecimal[log, ms];
    Put.Text[log, " ms to read and write something "L];
    Put.LongDecimal[log, cycles];
    Put.Line[log, " times."L];
    MultibusRpcControl.UnimportInterface[];
    Put.CR[log];
    END;

  EERom: FormSW.ProcType =
    BEGIN
    base: POINTER = LOOPHOLE[writePulse];
    noBind: BOOLEAN ← FALSE;
    MultibusRpcControl.ImportInterface[[NIL, target] !
      MesaRPC.ImportFailed =>
        BEGIN
	noBind ← TRUE;
	Put.Text[log, "Import from "L];
	Put.Text[log, target];
	Put.Text[log, " failed: "L];
	SELECT why FROM
	  communications => Put.Text[log, "communications"L];
	  badInstance => Put.Text[log, "badInstance"L];
	  badVersion => Put.Text[log, "badVersion"L];
	  wrongVersion => Put.Text[log, "wrongVersion"L];
	  unbound => Put.Text[log, "unbound"L];
	  stubProtocol => Put.Text[log, "stubProtocol"L];
	  ENDCASE => Put.Text[log, "??"L];
	Put.Line[log, "."L];
	CONTINUE;
	END];
    IF noBind THEN RETURN;
    FOR i: CARDINAL IN [0..2048) DO
      where: POINTER = base+i;
      data: WORD ← ReadWord[where];
      IF (i MOD 8H) = 0H THEN
        BEGIN
	IF UserInput.UserAbort[log] THEN EXIT;
        Put.CR[log];
        Put.Number[log, where, [16, FALSE, TRUE, 6]];
        Put.Text[log, "/ "L];
	END;
      Put.Number[log, data, [16, FALSE, TRUE, 5]];
      ENDLOOP;
      Put.CR[log];
    MultibusRpcControl.UnimportInterface[];
    Put.CR[log];
    END;

  Jim: FormSW.ProcType =
    BEGIN
    base: POINTER = LOOPHOLE[writePulse];
    noBind: BOOLEAN ← FALSE;
    MultibusRpcControl.ImportInterface[[NIL, target] !
      MesaRPC.ImportFailed =>
        BEGIN
	noBind ← TRUE;
	Put.Text[log, "Import from "L];
	Put.Text[log, target];
	Put.Text[log, " failed: "L];
	SELECT why FROM
	  communications => Put.Text[log, "communications"L];
	  badInstance => Put.Text[log, "badInstance"L];
	  badVersion => Put.Text[log, "badVersion"L];
	  wrongVersion => Put.Text[log, "wrongVersion"L];
	  unbound => Put.Text[log, "unbound"L];
	  stubProtocol => Put.Text[log, "stubProtocol"L];
	  ENDCASE => Put.Text[log, "??"L];
	Put.Line[log, "."L];
	CONTINUE;
	END];
    IF noBind THEN RETURN;
    FOR i: CARDINAL IN [0..2048) DO
      where: POINTER = base+i;
      data: WORD ← ReadByte[where, 4];
      IF (i MOD 10H) = 0H THEN
        BEGIN
	IF UserInput.UserAbort[log] THEN EXIT;
        Put.CR[log];
        Put.Number[log, where, [16, FALSE, TRUE, 6]];
        Put.Text[log, "/ "L];
	END;
      Put.Number[log, data, [16, FALSE, TRUE, 3]];
      ENDLOOP;
      Put.CR[log];
    MultibusRpcControl.UnimportInterface[];
    Put.CR[log];
    END;

  EPROM0: FormSW.ProcType =
    BEGIN
    base: POINTER = LOOPHOLE[0C000H];  -- 2764 needs high bits on
    noBind: BOOLEAN ← FALSE;
    MultibusRpcControl.ImportInterface[[NIL, target] !
      MesaRPC.ImportFailed =>
        BEGIN
	noBind ← TRUE;
	Put.Text[log, "Import from "L];
	Put.Text[log, target];
	Put.Text[log, " failed: "L];
	SELECT why FROM
	  communications => Put.Text[log, "communications"L];
	  badInstance => Put.Text[log, "badInstance"L];
	  badVersion => Put.Text[log, "badVersion"L];
	  wrongVersion => Put.Text[log, "wrongVersion"L];
	  unbound => Put.Text[log, "unbound"L];
	  stubProtocol => Put.Text[log, "stubProtocol"L];
	  ENDCASE => Put.Text[log, "??"L];
	Put.Line[log, "."L];
	CONTINUE;
	END];
    IF noBind THEN RETURN;
    FOR i: CARDINAL IN [0..8192) DO
      where: POINTER = base+i;
      data: WORD ← ReadByte[where, 0];
      IF (i MOD 10H) = 0H THEN
        BEGIN
	IF UserInput.UserAbort[log] THEN EXIT;
        Put.CR[log];
        Put.Number[log, where, [16, FALSE, TRUE, 6]];
        Put.Text[log, "/ "L];
	END;
      Put.Number[log, data, [16, FALSE, TRUE, 3]];
      ENDLOOP;
      Put.CR[log];
    MultibusRpcControl.UnimportInterface[];
    Put.CR[log];
    END;

  eprom: Multibus.IOAddress = MultibusAddresses.eprom;
  timeout: Multibus.IOAddress = MultibusAddresses.timeout;
  writePulse: WORD = 0800H;  -- NB: Low TRUE

  ReadWord: PROCEDURE [loc: POINTER] RETURNS [data: WORD] =
    BEGIN
    temp: Inline.BytePair;
    Multibus.Output[Inline.HighByte[loc], eprom + 00DH];  -- Port A Data
    Multibus.Output[Inline.LowByte[loc], eprom + 00EH];  -- Port B Data
    Multibus.Output[0FFH, timeout + 023H];  -- Port A Direction ← All in
    Multibus.Output[000H, eprom + 00FH];  -- Port C Data ← Output Enable
    Multibus.Output[005H, timeout + 00EH];  -- Port B Data ← High Byte
    temp.high ← Multibus.Input[timeout + 00DH];  -- Port A Data
    Multibus.Output[004H, timeout + 00EH];  -- Port B Data ← Low Byte
    temp.low ← Multibus.Input[timeout + 00DH];  -- Port A Data
    Multibus.Output[008H, eprom + 00FH];  -- Port C Data ← No Output Enable
    Multibus.Output[00FH, timeout + 00EH];  -- Port B Data ← Idle
    RETURN[LOOPHOLE[temp]];
    END;

  ReadByte: PROCEDURE [loc: POINTER, chip: CARDINAL] RETURNS [data: WORD] =
    BEGIN
    Multibus.Output[Inline.HighByte[loc], eprom + 00DH];  -- Port A Data
    Multibus.Output[Inline.LowByte[loc], eprom + 00EH];  -- Port B Data
    Multibus.Output[0FFH, timeout + 023H];  -- Port A Direction ← All in
    Multibus.Output[000H, eprom + 00FH];  -- Port C Data ← Output Enable
    Multibus.Output[chip, timeout + 00EH];  -- Port B Data ← High Byte
    data ← Multibus.Input[timeout + 00DH];  -- Port A Data
    Multibus.Output[008H, eprom + 00FH];  -- Port C Data ← No Output Enable
    Multibus.Output[00FH, timeout + 00EH];  -- Port B Data ← Idle
    END;

  Map: FormSW.ProcType =
    BEGIN
    noBind: BOOLEAN ← FALSE;
    map: LONG POINTER = LOOPHOLE[10000H];
    MultibusRpcControl.ImportInterface[[NIL, target] !
      MesaRPC.ImportFailed =>
        BEGIN
	noBind ← TRUE;
	Put.Text[log, "Import from "L];
	Put.Text[log, target];
	Put.Text[log, " failed: "L];
	SELECT why FROM
	  communications => Put.Text[log, "communications"L];
	  badInstance => Put.Text[log, "badInstance"L];
	  badVersion => Put.Text[log, "badVersion"L];
	  wrongVersion => Put.Text[log, "wrongVersion"L];
	  unbound => Put.Text[log, "unbound"L];
	  stubProtocol => Put.Text[log, "stubProtocol"L];
	  ENDCASE => Put.Text[log, "??"L];
	Put.Line[log, "."L];
	CONTINUE;
	END];
    IF noBind THEN RETURN;
    FOR i: CARDINAL IN [0..20) DO
      where: LONG POINTER = map + i;
      data: WORD ← Multibus.RawRead[where];
      Put.LongNumber[log, where, [16, FALSE, TRUE, 5]];
      Put.Text[log, "/ "L];
      Put.Number[log, data, [16, FALSE, TRUE, 5]];
      Put.CR[log];
      ENDLOOP;
    MultibusRpcControl.UnimportInterface[];
    Put.CR[log];
    END;

  Boot: FormSW.ProcType =
    BEGIN
    noBind: BOOLEAN ← FALSE;
    map: LONG POINTER = LOOPHOLE[10000H];
    MultibusRpcControl.ImportInterface[[NIL, target] !
      MesaRPC.ImportFailed =>
        BEGIN
	noBind ← TRUE;
	Put.Text[log, "Import from "L];
	Put.Text[log, target];
	Put.Text[log, " failed: "L];
	SELECT why FROM
	  communications => Put.Text[log, "communications"L];
	  badInstance => Put.Text[log, "badInstance"L];
	  badVersion => Put.Text[log, "badVersion"L];
	  wrongVersion => Put.Text[log, "wrongVersion"L];
	  unbound => Put.Text[log, "unbound"L];
	  stubProtocol => Put.Text[log, "stubProtocol"L];
	  ENDCASE => Put.Text[log, "??"L];
	Put.Line[log, "."L];
	CONTINUE;
	END];
    IF noBind THEN RETURN;
    FOR i: CARDINAL IN [0..100) DO
      ENABLE MesaRPC.CallFailed => EXIT;
      Multibus.Output[001H, timeout + 000H];  -- Master Interrupt Control ← Reset
      Multibus.Output[000H, timeout + 000H];  -- Master Interrupt Control ← No Reset
      Multibus.Output[00EH, timeout + 006H];  -- Port C Direction ← Bit 0 ← output
      Multibus.Output[000H, timeout + 00FH];  -- Port C Data ← 0
      Multibus.Output[010H, timeout + 001H];  -- Master Config Control ← Enable Port C
      Put.Char[log, '!];
      ENDLOOP;
    MultibusRpcControl.UnimportInterface[];
    Put.CR[log];
    END;

  Random: FormSW.ProcType =
    BEGIN
    noBind: BOOLEAN ← FALSE;
    ones, zeros, up, down: LONG CARDINAL ← 0;
    state: {idle, wasOne, wasZero} ← idle;
    MultibusRpcControl.ImportInterface[[NIL, target] !
      MesaRPC.ImportFailed =>
        BEGIN
	noBind ← TRUE;
	Put.Text[log, "Import from "L];
	Put.Text[log, target];
	Put.Text[log, " failed: "L];
	SELECT why FROM
	  communications => Put.Text[log, "communications"L];
	  badInstance => Put.Text[log, "badInstance"L];
	  badVersion => Put.Text[log, "badVersion"L];
	  wrongVersion => Put.Text[log, "wrongVersion"L];
	  unbound => Put.Text[log, "unbound"L];
	  stubProtocol => Put.Text[log, "stubProtocol"L];
	  ENDCASE => Put.Text[log, "??"L];
	Put.Line[log, "."L];
	CONTINUE;
	END];
    IF noBind THEN RETURN;
    FOR i: CARDINAL IN [0..5000) DO
      where: LONG POINTER = timeout + 00FH;  -- Port C Data
      data: WORD ← Multibus.Input[where];
      bit: WORD ← Inline.BITAND[data, 008H];
      IF i < 500 THEN
        BEGIN
        Put.Number[log, bit, [16, FALSE, TRUE, 1]];
        IF (i MOD 50) = 49 THEN Put.CR[log];
	END;
      IF bit = 0 THEN zeros ← zeros + 1
      ELSE ones ← ones + 1;
      SELECT state FROM
        idle => IF bit = 0 THEN state ← wasZero ELSE state ← wasOne;
	wasOne => BEGIN IF bit = 0 THEN down ← down + 1; state ← idle; END;
	wasZero => BEGIN IF bit # 0 THEN up ← up + 1; state ← idle; END;
	ENDCASE => ERROR;
      IF UserInput.UserAbort[log] THEN EXIT;
      ENDLOOP;
    MultibusRpcControl.UnimportInterface[];
    Put.Text[log, "Ones: "L];
    Put.LongDecimal[log, ones];
    Put.Text[log, " "L];
    Put.LongDecimal[log, ones*100/(ones+zeros)];
    Put.Text[log, "%,  Zeros: "L];
    Put.LongDecimal[log, zeros];
    Put.Text[log, " "L];
    Put.LongDecimal[log, zeros*100/(ones+zeros)];
    Put.Text[log, "%."L];
    Put.CR[log];
    IF (up + down) > 0 THEN
      BEGIN
      Put.Text[log, "Up: "L];
      Put.LongDecimal[log, up];
      Put.Text[log, " "L];
      Put.LongDecimal[log, up*100/(up+down)];
      Put.Text[log, "%,  Down: "L];
      Put.LongDecimal[log, down];
      Put.Text[log, " "L];
      Put.LongDecimal[log, down*100/(up+down)];
      Put.Text[log, "%."L];
      Put.CR[log];
      Put.Text[log, "Hit rate: "L];
      Put.LongDecimal[log, (up+down)*100/(ones+zeros)];
      Put.Text[log, "%."L];
      Put.CR[log];
      END;
    END;

  form, log: PUBLIC Window.Handle ← NIL;

  Init: PROCEDURE =
    BEGIN
    herald: STRING = [100];
    String.AppendString[herald, "TestFlukeServer of  "L];
    Time.Append[herald, Time.Unpack[Runtime.GetBcdTime[]]];
    [] ← Tool.Create[
      name: herald, makeSWsProc: MakeSWs,
      clientTransition: ClientTransition];
    END;

  MakeSWs: Tool.MakeSWsProc =
    BEGIN
    logFileName: STRING = [40];
    Tool.UnusedLogName[logFileName, "TestFlukeServer.log$"L];
    form ← Tool.MakeFormSW[window: window, formProc: MakeForm];
    log ← Tool.MakeFileSW[window: window, name: logFileName];
    END;

  MakeForm: FormSW.ClientItemsProcType =
    BEGIN
    nParams: CARDINAL = 8;
    items ← FormSW.AllocateItemDescriptor[nParams];
    items[0] ← FormSW.CommandItem[tag: "Echo"L, proc: Echo, place: FormSW.newLine];
    items[1] ← FormSW.CommandItem[tag: "EERom"L, proc: EERom];
    items[2] ← FormSW.CommandItem[tag: "Jim"L, proc: Jim];
    items[3] ← FormSW.CommandItem[tag: "EPROM0"L, proc: EPROM0];
    items[4] ← FormSW.CommandItem[tag: "Map"L, proc: Map];
    items[5] ← FormSW.CommandItem[tag: "Boot"L, proc: Boot];
    items[6] ← FormSW.CommandItem[tag: "Random"L, proc: Random];
    items[7] ← FormSW.StringItem[tag: "Target"L, string: @target, inHeap: TRUE];
    RETURN[items, TRUE];
    END;

  ClientTransition: ToolWindow.TransitionProcType =
    BEGIN IF new = inactive THEN form ← log ← NIL; END;

  Init[];

  END.