-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
-- TestMultibusPath.mesa, HGM,  7-May-83 18:41:16

DIRECTORY
  Environment USING [Block, Byte],
  FormSW USING [
    AllocateItemDescriptor, ClientItemsProcType, CommandItem,
    newLine, ProcType, StringItem],
  Format USING [StringProc],
  Inline USING [BITSHIFT, BITXOR, HighByte, LowByte],
  Process USING [Yield],
  Put USING [CR, Line, LongDecimal, Octal, Text],
  Runtime USING [GetBcdTime],
  String USING [AppendString],
  System USING [GetClockPulses, Microseconds, Pulses, PulsesToMicroseconds],
  TextSW USING [ForceOutput],
  Time USING [Append, Unpack],
  Tool USING [Create, MakeFormSW, MakeFileSW, MakeSWsProc, UnusedLogName],
  ToolWindow USING [TransitionProcType],
  UserInput USING [ReturnToNotifier, UserAbort],
  Window USING [Handle],
  
  CP USING [RealCS, wordsPerBank],
  CPMI USING [AD, AF, AS, FS01, FS23, FX, FY, FZ, MI],

  MesaRPC USING [ImportFailed],
  Multibus USING [IOAddress, Input, Output],
  MultibusAddresses USING [IOAddress, controlStore],
  MultibusRpcControl USING [ImportInterface, UnimportInterface];

TestMultibusPath: PROGRAM
  IMPORTS
    FormSW, Inline, Process, Put, Runtime, String, System,
    TextSW, Time, Tool, UserInput,
    MesaRPC, Multibus, MultibusRpcControl =
  BEGIN
  
  form, log: Window.Handle;
  target: LONG STRING ← NIL;
  
  wordsToTest: CARDINAL = CP.wordsPerBank;  -- Stomp on Kernel

  Error: SIGNAL [reason: LONG STRING] = CODE;
  Hickup: SIGNAL [reason: LONG STRING, cs: CP.RealCS, expected: CPMI.MI] = CODE;
  Three: TYPE = RECORD [a, b, c: WORD];
  
  WriteInfo: PROCEDURE [reason: LONG STRING, cs: CP.RealCS, expected: CPMI.MI] =
    BEGIN
    foo: Three = LOOPHOLE[expected];
    TailMessage[""L];
    NewMessage[reason];
    AppendMessage[": cs = "L];
    Put.Octal[log, cs];
    AppendMessage[", result = "L];
    Put.Octal[log, foo.a];
    AppendMessage[" "L];
    Put.Octal[log, foo.b];
    AppendMessage[" "L];
    Put.Octal[log, foo.c];
    TextSW.ForceOutput[log];
    END;

  TestBank1: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      Hickup =>
        BEGIN
	WriteInfo[reason, cs, expected];
	IF UserInput.UserAbort[log] THEN CONTINUE;
        RESUME;
        END;
      END;
    PostMessage["Testing Bank 1 of control store (! = 64 wds)"L];
    MakeContact[];
    TailMessage[""L];
    FOR cs: CP.RealCS IN [1*CP.wordsPerBank..1*wordsToTest+CP.wordsPerBank) DO
      zeros: CPMI.MI = LOOPHOLE[Three[0, 0, 0]];
      ones: CPMI.MI = LOOPHOLE[Three[177777B, 177777B, 177777B]];
      address: CPMI.MI = LOOPHOLE[Three[cs, 0, cs]];  -- parity
      result: CPMI.MI;
      IF UserInput.UserAbort[log] THEN EXIT;
      SELECT TRUE FROM
        (cs = CP.wordsPerBank) => NULL;
        ((cs MOD 64) = 0) => AppendMessage["!"L];
	ENDCASE => NULL;
      WriteCS[cs, zeros];
      result ← ReadCS[cs];
      IF result # zeros THEN SIGNAL Hickup["Didn't get zeros back"L, cs, result];
      WriteCS[cs, ones];
      result ← ReadCS[cs];
      IF result # ones THEN SIGNAL Hickup["Didn't get ones back"L, cs, result];
      WriteCS[cs, address];
      result ← ReadCS[cs];
      IF result # address THEN SIGNAL Hickup["Didn't get address back"L, cs, result];
      Process.Yield[];
      ENDLOOP;
    TailMessage[" ok"L];
    IF UserInput.UserAbort[log] THEN RETURN;
    NewMessage["Check pass ... (! = 64 wds)"L];
    TailMessage[""L];
    FOR cs: CP.RealCS IN [1*CP.wordsPerBank..1*wordsToTest+CP.wordsPerBank) DO
      address: CPMI.MI = LOOPHOLE[Three[cs, 0, cs]];
      result: CPMI.MI;
      IF UserInput.UserAbort[log] THEN EXIT;
      SELECT TRUE FROM
        (cs = CP.wordsPerBank) => NULL;
        ((cs MOD 64) = 0) => AppendMessage["!"L];
	ENDCASE => NULL;
      result ← ReadCS[cs];
      IF result # address THEN SIGNAL Hickup["Didn't get address back"L, cs, result];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
  
  WriteBank1: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      END;
    PostMessage["Writing Bank 1 of control store"L];
    MakeContact[];
    TailMessage[""L];
    UNTIL UserInput.UserAbort[log] DO
      FOR cs: CP.RealCS IN [1*CP.wordsPerBank..1*wordsToTest+CP.wordsPerBank) DO
        zeros: CPMI.MI = LOOPHOLE[Three[0, 0, 0]];
        ones: CPMI.MI = LOOPHOLE[Three[177777B, 177777B, 177777B]];
        IF UserInput.UserAbort[log] THEN EXIT;
        WriteCS[cs, zeros];
        WriteCS[cs, ones];
        Process.Yield[];
        ENDLOOP;
      AppendMessage["!"L];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
      
  ReadBank1: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      END;
    PostMessage["Reading Bank 1 of control store"L];
    MakeContact[];
    TailMessage[""L];
    UNTIL UserInput.UserAbort[log] DO
      FOR cs: CP.RealCS IN [1*CP.wordsPerBank..1*wordsToTest+CP.wordsPerBank) DO
        IF UserInput.UserAbort[log] THEN EXIT;
        [] ← ReadCS[cs];
        Process.Yield[];
        ENDLOOP;
      AppendMessage["!"L];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
      
  WriteReadBank1: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      END;
    PostMessage["Writing and Reading Bank 1 of control store"L];
    MakeContact[];
    TailMessage[""L];
    UNTIL UserInput.UserAbort[log] DO
      FOR cs: CP.RealCS IN [1*CP.wordsPerBank..wordsToTest+1*CP.wordsPerBank) DO
        zeros: CPMI.MI = LOOPHOLE[Three[0, 0, 0]];
        ones: CPMI.MI = LOOPHOLE[Three[177777B, 177777B, 177777B]];
        IF UserInput.UserAbort[log] THEN EXIT;
        WriteCS[cs, zeros];
        [] ← ReadCS[cs];
        WriteCS[cs, ones];
        [] ← ReadCS[cs];
        Process.Yield[];
        ENDLOOP;
      AppendMessage["!"L];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
      
  TestBank2: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      Hickup =>
        BEGIN
	WriteInfo[reason, cs, expected];
	IF UserInput.UserAbort[log] THEN CONTINUE;
        RESUME;
        END;
      END;
    PostMessage["Testing Bank 2 of control store (! = 64 wds)"L];
    MakeContact[];
    TailMessage[""L];
    FOR cs: CP.RealCS IN [2*CP.wordsPerBank..2*wordsToTest+CP.wordsPerBank) DO
      zeros: CPMI.MI = LOOPHOLE[Three[0, 0, 0]];
      ones: CPMI.MI = LOOPHOLE[Three[177777B, 177777B, 177777B]];
      address: CPMI.MI = LOOPHOLE[Three[cs, 0, cs]];  -- parity
      result: CPMI.MI;
      IF UserInput.UserAbort[log] THEN EXIT;
      SELECT TRUE FROM
        (cs = CP.wordsPerBank) => NULL;
        ((cs MOD 64) = 0) => AppendMessage["!"L];
	ENDCASE => NULL;
      WriteCS[cs, zeros];
      result ← ReadCS[cs];
      IF result # zeros THEN SIGNAL Hickup["Didn't get zeros back"L, cs, result];
      WriteCS[cs, ones];
      result ← ReadCS[cs];
      IF result # ones THEN SIGNAL Hickup["Didn't get ones back"L, cs, result];
      WriteCS[cs, address];
      result ← ReadCS[cs];
      IF result # address THEN SIGNAL Hickup["Didn't get address back"L, cs, result];
      Process.Yield[];
      ENDLOOP;
    TailMessage[" ok"L];
    IF UserInput.UserAbort[log] THEN RETURN;
    NewMessage["Check pass ... (! = 64 wds)"L];
    TailMessage[""L];
    FOR cs: CP.RealCS IN [2*CP.wordsPerBank..2*wordsToTest+CP.wordsPerBank) DO
      address: CPMI.MI = LOOPHOLE[Three[cs, 0, cs]];
      result: CPMI.MI;
      IF UserInput.UserAbort[log] THEN EXIT;
      SELECT TRUE FROM
        (cs = CP.wordsPerBank) => NULL;
        ((cs MOD 64) = 0) => AppendMessage["!"L];
	ENDCASE => NULL;
      result ← ReadCS[cs];
      IF result # address THEN SIGNAL Hickup["Didn't get address back"L, cs, result];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
  
  WriteBank2: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      END;
    PostMessage["Writing Bank 2 of control store"L];
    MakeContact[];
    TailMessage[""L];
    UNTIL UserInput.UserAbort[log] DO
      FOR cs: CP.RealCS IN [2*CP.wordsPerBank..2*wordsToTest+CP.wordsPerBank) DO
        zeros: CPMI.MI = LOOPHOLE[Three[0, 0, 0]];
        ones: CPMI.MI = LOOPHOLE[Three[177777B, 177777B, 177777B]];
        IF UserInput.UserAbort[log] THEN EXIT;
        WriteCS[cs, zeros];
        WriteCS[cs, ones];
        Process.Yield[];
        ENDLOOP;
      AppendMessage["!"L];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
      
  ReadBank2: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      END;
    PostMessage["Reading Bank 2 of control store"L];
    MakeContact[];
    TailMessage[""L];
    UNTIL UserInput.UserAbort[log] DO
      FOR cs: CP.RealCS IN [2*CP.wordsPerBank..2*wordsToTest+CP.wordsPerBank) DO
        IF UserInput.UserAbort[log] THEN EXIT;
        [] ← ReadCS[cs];
        Process.Yield[];
        ENDLOOP;
      AppendMessage["!"L];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
      
  WriteReadBank2: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      END;
    PostMessage["Writing and Reading Bank 2 of control store"L];
    MakeContact[];
    TailMessage[""L];
    UNTIL UserInput.UserAbort[log] DO
      FOR cs: CP.RealCS IN [2*CP.wordsPerBank..wordsToTest+2*CP.wordsPerBank) DO
        zeros: CPMI.MI = LOOPHOLE[Three[0, 0, 0]];
        ones: CPMI.MI = LOOPHOLE[Three[177777B, 177777B, 177777B]];
        IF UserInput.UserAbort[log] THEN EXIT;
        WriteCS[cs, zeros];
        [] ← ReadCS[cs];
        WriteCS[cs, ones];
        [] ← ReadCS[cs];
        Process.Yield[];
        ENDLOOP;
      AppendMessage["!"L];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
      
  TestBank3: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      Hickup =>
        BEGIN
	WriteInfo[reason, cs, expected];
	IF UserInput.UserAbort[log] THEN CONTINUE;
        RESUME;
        END;
      END;
    PostMessage["Testing Bank 3 of control store (! = 64 wds)"L];
    MakeContact[];
    TailMessage[""L];
    FOR cs: CP.RealCS IN [3*CP.wordsPerBank..3*wordsToTest+CP.wordsPerBank) DO
      zeros: CPMI.MI = LOOPHOLE[Three[0, 0, 0]];
      ones: CPMI.MI = LOOPHOLE[Three[177777B, 177777B, 177777B]];
      address: CPMI.MI = LOOPHOLE[Three[cs, 0, cs]];  -- parity
      result: CPMI.MI;
      IF UserInput.UserAbort[log] THEN EXIT;
      SELECT TRUE FROM
        (cs = CP.wordsPerBank) => NULL;
        ((cs MOD 64) = 0) => AppendMessage["!"L];
	ENDCASE => NULL;
      WriteCS[cs, zeros];
      result ← ReadCS[cs];
      IF result # zeros THEN SIGNAL Hickup["Didn't get zeros back"L, cs, result];
      WriteCS[cs, ones];
      result ← ReadCS[cs];
      IF result # ones THEN SIGNAL Hickup["Didn't get ones back"L, cs, result];
      WriteCS[cs, address];
      result ← ReadCS[cs];
      IF result # address THEN SIGNAL Hickup["Didn't get address back"L, cs, result];
      Process.Yield[];
      ENDLOOP;
    TailMessage[" ok"L];
    IF UserInput.UserAbort[log] THEN RETURN;
    NewMessage["Check pass ... (! = 64 wds)"L];
    TailMessage[""L];
    FOR cs: CP.RealCS IN [3*CP.wordsPerBank..3*wordsToTest+CP.wordsPerBank) DO
      address: CPMI.MI = LOOPHOLE[Three[cs, 0, cs]];
      result: CPMI.MI;
      IF UserInput.UserAbort[log] THEN EXIT;
      SELECT TRUE FROM
        (cs = CP.wordsPerBank) => NULL;
        ((cs MOD 64) = 0) => AppendMessage["!"L];
	ENDCASE => NULL;
      result ← ReadCS[cs];
      IF result # address THEN SIGNAL Hickup["Didn't get address back"L, cs, result];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
  
  WriteBank3: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      END;
    PostMessage["Writing Bank 3 of control store"L];
    MakeContact[];
    TailMessage[""L];
    UNTIL UserInput.UserAbort[log] DO
      FOR cs: CP.RealCS IN [3*CP.wordsPerBank..3*wordsToTest+CP.wordsPerBank) DO
        zeros: CPMI.MI = LOOPHOLE[Three[0, 0, 0]];
        ones: CPMI.MI = LOOPHOLE[Three[177777B, 177777B, 177777B]];
        IF UserInput.UserAbort[log] THEN EXIT;
        WriteCS[cs, zeros];
        WriteCS[cs, ones];
        Process.Yield[];
        ENDLOOP;
      AppendMessage["!"L];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
      
  ReadBank3: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      END;
    PostMessage["Reading Bank 3 of control store"L];
    MakeContact[];
    TailMessage[""L];
    UNTIL UserInput.UserAbort[log] DO
      FOR cs: CP.RealCS IN [3*CP.wordsPerBank..3*wordsToTest+CP.wordsPerBank) DO
        IF UserInput.UserAbort[log] THEN EXIT;
        [] ← ReadCS[cs];
        Process.Yield[];
        ENDLOOP;
      AppendMessage["!"L];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
      
  WriteReadBank3: FormSW.ProcType =
    BEGIN ENABLE
      BEGIN
      Error =>
        BEGIN
        TailMessage[reason];
        CONTINUE;
        END;
      END;
    PostMessage["Writing and Reading Bank 3 of control store"L];
    MakeContact[];
    TailMessage[""L];
    UNTIL UserInput.UserAbort[log] DO
      FOR cs: CP.RealCS IN [3*CP.wordsPerBank..wordsToTest+3*CP.wordsPerBank) DO
        zeros: CPMI.MI = LOOPHOLE[Three[0, 0, 0]];
        ones: CPMI.MI = LOOPHOLE[Three[177777B, 177777B, 177777B]];
        IF UserInput.UserAbort[log] THEN EXIT;
        WriteCS[cs, zeros];
        [] ← ReadCS[cs];
        WriteCS[cs, ones];
        [] ← ReadCS[cs];
        Process.Yield[];
        ENDLOOP;
      AppendMessage["!"L];
      ENDLOOP;
    TailMessage[" ok"L];
    END;
      
  LogString: Format.StringProc =
    BEGIN
    Put.Text[clientData, s];
    END;

  PostMessage: PROCEDURE [s: LONG STRING, clear: BOOLEAN ← TRUE] =
    BEGIN
    Put.CR[log];
    Put.Text[log, s];
    TextSW.ForceOutput[log]
    END;

  NewMessage: PROCEDURE [s: LONG STRING, clear: BOOLEAN ← TRUE] =
    BEGIN
    Put.Text[log, s];
    TextSW.ForceOutput[log]
    END;

  AppendMessage: PROCEDURE [s: LONG STRING] =
    BEGIN
    Put.Text[log, s];
    TextSW.ForceOutput[log]
    END;

  TailMessage: PROCEDURE [s: LONG STRING] =
    BEGIN
    Put.Text[log, s];
    Put.Line[log, "."L];
    TextSW.ForceOutput[log]
    END;

  Initialize: PROCEDURE =
    BEGIN
    herald: STRING = [100];
    String.AppendString[herald, "TestMultibusPath of  "L];
    Time.Append[herald, Time.Unpack[Runtime.GetBcdTime[]]];
    [] ← Tool.Create[
      name: herald,
      cmSection: "TestMultibusPath"L,
      makeSWsProc: MakeSWs,
      clientTransition: ClientTransition];
    END;
  
  MakeSWs: Tool.MakeSWsProc =
    BEGIN
    logFileName: STRING = [40];
    form ← Tool.MakeFormSW[window: window, formProc: MakeForm];
    Tool.UnusedLogName[logFileName, "CSBankTester.log$"L];
    log ← Tool.MakeFileSW[window: window, name: logFileName];
    END;
  
  MakeForm: FormSW.ClientItemsProcType =
    BEGIN
    i: INTEGER ← -1;
    nParams: CARDINAL = 13;
    items ← FormSW.AllocateItemDescriptor[nParams];
    items[i←i+1] ← FormSW.StringItem[tag: "Target"L, string: @target, inHeap: TRUE, place: FormSW.newLine];
    items[i←i+1] ← FormSW.CommandItem[tag: "TestBank1"L, proc: TestBank1, place: FormSW.newLine];
    items[i←i+1] ← FormSW.CommandItem[tag: "WriteBank1"L, proc: WriteBank1];
    items[i←i+1] ← FormSW.CommandItem[tag: "ReadBank1"L, proc: ReadBank1];
    items[i←i+1] ← FormSW.CommandItem[tag: "WriteReadBank1"L, proc: WriteReadBank1];
    items[i←i+1] ← FormSW.CommandItem[tag: "TestBank2"L, proc: TestBank2, place: FormSW.newLine];
    items[i←i+1] ← FormSW.CommandItem[tag: "WriteBank2"L, proc: WriteBank2];
    items[i←i+1] ← FormSW.CommandItem[tag: "ReadBank2"L, proc: ReadBank2];
    items[i←i+1] ← FormSW.CommandItem[tag: "WriteReadBank2"L, proc: WriteReadBank2];
    items[i←i+1] ← FormSW.CommandItem[tag: "TestBank3"L, proc: TestBank3, place: FormSW.newLine];
    items[i←i+1] ← FormSW.CommandItem[tag: "WriteBank3"L, proc: WriteBank3];
    items[i←i+1] ← FormSW.CommandItem[tag: "ReadBank3"L, proc: ReadBank3];
    items[i←i+1] ← FormSW.CommandItem[tag: "WriteReadBank3"L, proc: WriteReadBank3];
    IF (i+1) # nParams THEN ERROR;
    RETURN[items, TRUE];
    END;
     
  ClientTransition: ToolWindow.TransitionProcType =
    BEGIN
    SELECT TRUE FROM
      old = inactive =>
        BEGIN
        END;
      new = inactive =>
        BEGIN
        END;
      ENDCASE;
    END;
    
  -- Adapted from CPKernelCSDicentra
  
  ReadCS: PROCEDURE [real: CP.RealCS] RETURNS [CPMI.MI] =
    BEGIN
    block: Environment.Block ← [LOOPHOLE[LONG[@data]], 0, 2*SIZE[MIReal]];
    data: MIReal;
    WriteWord[csaMsb, real];
    ReadBlock[csData0, block];
    RETURN[RealToVirtural[data]];
    END;
	
  WriteCS: PROCEDURE [real: CP.RealCS, mi: CPMI.MI] =
    BEGIN
    realMi: MIReal ← VirturalToReal[mi];
    words: POINTER = @realMi;
    temp: PACKED ARRAY [0..8) OF Environment.Byte;
    block: Environment.Block ← [LOOPHOLE[LONG[@temp]], 0, 8];
    FixParity[@realMi];
    temp[0] ← Inline.HighByte[real];
    temp[1] ← Inline.LowByte[real];
    temp[2] ← Inline.HighByte[(words+0)↑];
    temp[3] ← Inline.LowByte[(words+0)↑];
    temp[4] ← Inline.HighByte[(words+1)↑];
    temp[5] ← Inline.LowByte[(words+1)↑];
    temp[6] ← Inline.HighByte[(words+2)↑];
    temp[7] ← Inline.LowByte[(words+2)↑];
    WriteBlock[csaMsb, block];
    END;
	
  FixParity: PROCEDURE [data: LONG POINTER TO MIReal] =
    BEGIN
    words: LONG POINTER = data;
    parity: WORD ← 0;
    data.ep ← FALSE;
    FOR i: CARDINAL IN [0..SIZE[MIReal]) DO
      parity ← Inline.BITXOR[parity, (words+i)↑];
      ENDLOOP;
    parity ← Inline.BITXOR[parity, Inline.BITSHIFT[parity, -8]];
    parity ← Inline.BITXOR[parity, Inline.BITSHIFT[parity, -4]];
    parity ← Inline.BITXOR[parity, Inline.BITSHIFT[parity, -2]];
    parity ← Inline.BITXOR[parity, Inline.BITSHIFT[parity, -1]];
    data.ep ← LOOPHOLE[parity];
    END;

  MIReal: TYPE = MACHINE DEPENDENT RECORD [
    rA, rB: [0..0FH],
    aS: CPMI.AS, aF: CPMI.AF,
    aD: CPMI.AD,  --word 0
    ep, cIn, enSU, mem: BOOLEAN,
    fS01: CPMI.FS01, fS23: CPMI.FS23,
    fX: CPMI.FX, fY: CPMI.FY,  --word 1
    fZ: CPMI.FZ, inia: [0..CP.wordsPerBank)];  --word 2

  -- See also FixupMI in MakeControlStoreMB
  VirturalToReal: PROCEDURE [virtural: CPMI.MI] RETURNS [real: MIReal] =
    BEGIN
    mir: POINTER TO MIReal = @real;
    miv: POINTER TO CPMI.MI = @virtural;
    BEGIN OPEN miv;
    mir↑ ← [
      rA, rB, aS, aF, aD, ep, cIn, enSU, mem, fS01, fS23, fX, fY, fZ, Inline.BITXOR[inia,17B]]
    END
    END;

  RealToVirtural: PROCEDURE [real: MIReal] RETURNS [virtural: CPMI.MI] =
    BEGIN
    mir: POINTER TO MIReal = @real;
    miv: POINTER TO CPMI.MI = @virtural;
    BEGIN OPEN mir;
    miv↑ ← [
      rA, rB, aS, aF, aD, ep, cIn, enSU, mem, fS01, fS23, fX, fY, fZ, Inline.BITXOR[inia,17B]]
    END;
    END;


  -- Copied from Teather and/or TestDebuggerBoard

  baseAddress: MultibusAddresses.IOAddress = MultibusAddresses.controlStore;
  finger: MultibusAddresses.IOAddress = baseAddress + 0;
  contents: MultibusAddresses.IOAddress = baseAddress + 1;

  Register: TYPE = MACHINE DEPENDENT {
    -- Control Store section starts at 0
    csaMsb(0B), csaLsb(1B),
    csData0(2B), csData1(3B), csData2(4B), csData3(5B), csData4(6B), csData5(7B),
    niaMsb(10B), niaLsb(11B),
    temp(12B),
    -- History Buffer section starts at 20B
    hbAddr(20B),
    hbPCMsb(21B), hbPCLsb(22B), hbPCExtra(23B),
    hbMatchMsb(24B), hbMatchLsb(25B),
    hbCount(26B), hbBits(27B),
    (377B) };
  
  WriteWord: PROCEDURE [reg: Register, data: WORD] =
    BEGIN
    Multibus.Output[reg, finger];
    Multibus.Output[Inline.HighByte[data], contents];
    Multibus.Output[Inline.LowByte[data], contents];
    END;
    
  ReadBlock: PROCEDURE [reg: Register, block: Environment.Block] =
    BEGIN
    Multibus.Output[reg, finger];
    FOR i: CARDINAL IN [block.startIndex..block.stopIndexPlusOne) DO
      block.blockPointer[i] ← Multibus.Input[contents];
      ENDLOOP;
    END;
    
  WriteBlock: PROCEDURE [reg: Register, block: Environment.Block] =
    BEGIN
    Multibus.Output[reg, finger];
    FOR i: CARDINAL IN [block.startIndex..block.stopIndexPlusOne) DO
      Multibus.Output[block.blockPointer[i], contents];
      ENDLOOP;
    END;
    


  -- From TestFlukeServer

  bound: BOOLEAN ← FALSE;
  MakeContact: PROCEDURE =
    BEGIN
    start, end: System.Pulses;
    ms: LONG CARDINAL;
    IF bound THEN MultibusRpcControl.UnimportInterface[];
    bound ← FALSE;
    start ← System.GetClockPulses[];
    MultibusRpcControl.ImportInterface[[NIL, target] !
      MesaRPC.ImportFailed =>
        BEGIN
	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];
        UserInput.ReturnToNotifier["Import failed"L];
	END];
    bound ← TRUE;
    end ← System.GetClockPulses[];
    ms ← System.PulsesToMicroseconds[[end-start]]/1000;
    Put.Line[log, "."L];
    Put.Text[log, "It took "L];
    Put.LongDecimal[log, ms];
    Put.Text[log, " ms to Import Multibus"L];
    END;

  Initialize[];
  END.