-- Copyright (C) 1983, 1985  by Xerox Corporation. All rights reserved. 
-- EERomDicentra.mesa, HGM,  6-Apr-85 11:38:58

DIRECTORY
  Environment USING [Byte, bytesPerWord],
  Inline USING [LowByte, HighByte],
  Process USING [Pause],
  System USING [GetClockPulses, Pulses, PulsesToMicroseconds],
  DicentraInputOutput USING [Input, IOAddress, Output],
  EERom USING [BootLocation, bytesPerChip, Data, WholeEERom],
  MultibusAddresses USING [eprom, timeout];

EERomDicentra: MONITOR
  IMPORTS Inline, Process, System, DicentraInputOutput EXPORTS EERom =
  BEGIN
  
  eprom: DicentraInputOutput.IOAddress = MultibusAddresses.eprom;
  timeout: DicentraInputOutput.IOAddress = MultibusAddresses.timeout;
  
  -- Port A on Timeout CIO was enabled by Microcode/ProcessorHead.
  eeRom: POINTER TO EERom.WholeEERom = LOOPHOLE[0];
  writePulse: WORD = 0800H;  -- NB: Low TRUE
  firstChip: CARDINAL = 4;

  ReadByte: PROCEDURE [loc: POINTER, offset: CARDINAL] RETURNS [data: Environment.Byte] =
    BEGIN
    byteIndex, chip, byteWithinChip: CARDINAL;
    byteIndex ← Environment.bytesPerWord*LOOPHOLE[loc, CARDINAL] + offset;
    chip ← firstChip + (byteIndex / EERom.bytesPerChip);
    byteWithinChip ← byteIndex MOD EERom.bytesPerChip;
    byteWithinChip ← byteWithinChip + writePulse;
    DicentraInputOutput.Output[Inline.HighByte[byteWithinChip], eprom + 00DH];  -- Port A Data
    DicentraInputOutput.Output[Inline.LowByte[byteWithinChip], eprom + 00EH];  -- Port B Data
    DicentraInputOutput.Output[0FFH, timeout + 023H];  -- Port A Direction ← All in
    DicentraInputOutput.Output[000H, eprom + 00FH];  -- Port C Data ← Output Enable
    DicentraInputOutput.Output[chip, timeout + 00EH];  -- Port B Data
    data ← DicentraInputOutput.Input[timeout + 00DH];  -- Port A Data
    DicentraInputOutput.Output[008H, eprom + 00FH];  -- Port C Data ← No Output Enable
    DicentraInputOutput.Output[00FH, timeout + 00EH];  -- Port B Data ← Idle
    END;

  WriteByte: PROCEDURE [loc: POINTER, offset: CARDINAL, data: Environment.Byte] =
    BEGIN
    byteIndex, chip, byteWithinChip: CARDINAL;
    IF data = ReadByte[loc, offset] THEN RETURN;
    byteIndex ← Environment.bytesPerWord*LOOPHOLE[loc, CARDINAL] + offset;
    chip ← firstChip + (byteIndex / EERom.bytesPerChip);
    byteWithinChip ← byteIndex MOD EERom.bytesPerChip;
    byteWithinChip ← byteWithinChip + writePulse;
    DicentraInputOutput.Output[Inline.HighByte[byteWithinChip], eprom + 00DH];  -- Port A Data
    DicentraInputOutput.Output[Inline.LowByte[byteWithinChip], eprom + 00EH];  -- Port B Data
    DicentraInputOutput.Output[008H, eprom + 00FH];  -- Port C Data ← No Output Enable
    DicentraInputOutput.Output[000H, timeout + 023H];  -- Port A Direction ← All out
    DicentraInputOutput.Output[chip, timeout + 00EH];  -- Port B Data ← High Byte
    DicentraInputOutput.Output[data, timeout + 00DH];  -- Port A Data
    byteWithinChip ← byteWithinChip - writePulse;
    DicentraInputOutput.Output[Inline.HighByte[byteWithinChip], eprom + 00DH];  -- Port A Data
    byteWithinChip ← byteWithinChip + writePulse;
    DicentraInputOutput.Output[Inline.HighByte[byteWithinChip], eprom + 00DH];  -- Port A Data
    WaitTenMs[];
    DicentraInputOutput.Output[0FFH, timeout + 023H];  -- Port A Direction ← All in
    DicentraInputOutput.Output[00FH, timeout + 00EH];  -- Port B Data ← Idle
    END;

  StoreBootLocation: PUBLIC ENTRY PROCEDURE [bits: LONG POINTER TO EERom.BootLocation] =
    BEGIN
    info: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ← LOOPHOLE[bits];
    address: POINTER ← @eeRom.bootLocation;
    FOR i: CARDINAL IN [0..Environment.bytesPerWord*SIZE[EERom.BootLocation]) DO
      WriteByte[address, i, info[i]];
      ENDLOOP;
    END;
    
  FetchBootLocation: PUBLIC ENTRY PROCEDURE [bits: LONG POINTER TO EERom.BootLocation] =
    BEGIN
    info: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ← LOOPHOLE[bits];
    address: POINTER ← @eeRom.bootLocation;
    FOR i: CARDINAL IN [0..Environment.bytesPerWord*SIZE[EERom.BootLocation]) DO
      info[i] ← ReadByte[address, i];
      ENDLOOP;
    END;
  
  StoreData: PUBLIC ENTRY PROCEDURE [bits: LONG POINTER TO EERom.Data] =
    BEGIN
    info: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ← LOOPHOLE[bits];
    address: POINTER ← @eeRom.data;
    FOR i: CARDINAL IN [0..Environment.bytesPerWord*SIZE[EERom.Data]) DO
      WriteByte[address, i, info[i]];
      ENDLOOP;
    END;
  
  FetchData: PUBLIC ENTRY PROCEDURE [bits: LONG POINTER TO EERom.Data] =
    BEGIN
    info: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ← LOOPHOLE[bits];
    address: POINTER ← @eeRom.data;
    FOR i: CARDINAL IN [0..Environment.bytesPerWord*SIZE[EERom.Data]) DO
      info[i] ← ReadByte[address, i];
      ENDLOOP;
    END;
  
  SmashData: PUBLIC ENTRY PROCEDURE =
    BEGIN
    address: POINTER ← @eeRom.data;
    FOR i: CARDINAL IN [0..Environment.bytesPerWord*SIZE[EERom.Data]) DO
      WriteByte[address, i, 0];
      ENDLOOP;
    END;
  
  -- Spec says we need to wait 10ms.  That seemed to fail occasionally.
  -- Spinning for 20ms lets the watchdog timer go off. This will probably take 50ms.
  WaitTenMs: PROCEDURE =
    BEGIN
    start: System.Pulses = System.GetClockPulses[];
    DO
      now: System.Pulses = System.GetClockPulses[];
      IF System.PulsesToMicroseconds[[now-start]] > 20000 THEN EXIT;
      Process.Pause[1];
      ENDLOOP;
    END;
    
  END.