// PupAlEIAa.bcpl - PUP level -1 driver for EIA Interface
// Copyright Xerox Corporation 1979

// Last modified October 1, 1978  5:07 PM

get "Pup0.decl"
get "PupAlEIA.decl"

external
[
// outgoing procedures
EIAFinishProc; EIASwatContextProc; EIAInterrupt
StartEIAT; StopEIAT; StartEIAR; StopEIAR

// incoming procedures
EIAOutputDone; EIAInputDone
Enqueue; Dequeue
DisableInterrupts; EnableInterrupts; DestroyInterrupt

// incoming statics
pbiFreeQ; lenPup; eiaNDB; eiaLT
savedEIAFinishProc; lvUserFinishProc; lvSwatContextProc
]

static savedEIASwatProc

//----------------------------------------------------------------------------
let EIAFinishProc() be
//----------------------------------------------------------------------------
[
//Disable the EIA microcode.
(table [ mcEnableEIA; #1401 ])(0)
DestroyInterrupt(eiaNDB>>EIANDB.lcb↑0.iEIALCB>>EIALCB.intMask)
@lvUserFinishProc = savedEIAFinishProc
@lvSwatContextProc = savedEIASwatProc
]

//----------------------------------------------------------------------------
and EIASwatContextProc() be
//----------------------------------------------------------------------------
[
let t = table
   [
   #101005	// mov 0 0 snr		; skip if turn on
   #102401	//  mkzero 0 0 skp	; entering.  Turn off eia
   #020403	// lda 0 .+3		; leaving.  Turn on eia
   #063400	// EnableEIA
   #001401	// jmp 1 3
   0		// -> eiaLT
   ]
t!5 = eiaLT
savedEIASwatProc = @lvSwatContextProc
@lvSwatContextProc = t
]

//----------------------------------------------------------------------------
and EIAInterrupt() be
//----------------------------------------------------------------------------
// Control comes here when the EIA microcode interrupts.
[
for line = 0 to maxLine do if eiaLT>>EIALT.eiaLTE↑line.exists then
   [
   let lcb = lv eiaNDB>>EIANDB.lcb↑line

   //Check input LCBs.
   let eiaLCB = lcb>>LCB.iEIALCB
   let firmStatus = eiaLCB>>EIALCB.firmStatus
   if firmStatus ls 0 then
      [
      //Dont look here again for a completed EIALCB
      eiaLCB>>EIALCB.firmStatus = 0

      //Take care of any errors that might have occured.
      switchon (firmStatus & 77777B) into
         [
         case errorNone:
            [
            lcb>>LCB.iPBI>>PBI.packetLength =
             ((lenPup+1) lshift 1) - (eiaLCB>>EIALCB.byteCount & 77777B)
            EIAInputDone(lcb)
            endcase
            ]
         case errorFatal:
            [
            StopEIAR(lcb)
            endcase
            ]
         case errorETX:
            [
            lcb>>LCB.inputOverrun = lcb>>LCB.inputOverrun +1
            endcase
            ]
         case errorSTX:
         case errorDLE:
            [
            lcb>>LCB.lineControlError = lcb>>LCB.lineControlError +1
            endcase
            ]
         case errorCRC:
            [
            lcb>>LCB.badCRC = lcb>>LCB.badCRC +1
            endcase
            ]
         ]
      //Restart reception of packets.
      if lcb>>LCB.iPBI eq 0 then
         lcb>>LCB.iPBI = Dequeue(pbiFreeQ)
      if lcb>>LCB.iPBI ne 0 then StartEIAR(lcb)
      ]

//EIAInterrupt (cont'd)

   //check output LCBs.
   eiaLCB = lcb>>LCB.oEIALCB
   firmStatus = eiaLCB>>EIALCB.firmStatus
   if firmStatus ls 0 then
      [
      //Dont look here again for a completed EIALCB
      eiaLCB>>EIALCB.firmStatus = 0

      //Take care of any errors that might have occured.
      switchon (firmStatus & 77777B) into
         [
         case errorFatal: StopEIAT(lcb)  //fall through
         case errorNone:
            [
            EIAOutputDone(lcb)
            endcase
            ]
         default: StartEIAT(lcb)
         ]
      ]
   ]
]

//----------------------------------------------------------------------------
and StartEIAR(lcb) be
//----------------------------------------------------------------------------
// Start EIA reception of a packet over the line represented by the LCB.
// This procedure is called by InitAltoEIA to start things up,
// by EIAInterrupt when an input is complete to restart reception, and
// by EIAProcess to restart reception on a line that ran out of PBIs.
[
DisableInterrupts()
let eiaLCB = lcb>>LCB.iEIALCB

//Set up to input into iPBI.
eiaLCB>>EIALCB.byteCount = (lenPup+1) lshift 1
eiaLCB>>EIALCB.bytePointer = lv (lcb>>LCB.iPBI)>>EIAPBI.type
eiaLCB>>EIALCB.firmStatus = 0
eiaLCB>>EIALCB.hardStatus = 0
eiaLCB>>EIALCB.partialCRC = 0

//Link the EIALCB to the line's LTE.
//The microcode is always watching for this to go non-zero.
eiaLT>>EIALT.eiaLTE↑(lcb>>LCB.line).iLCB = eiaLCB
EnableInterrupts()
]

//----------------------------------------------------------------------------
and StopEIAR(lcb) be
//----------------------------------------------------------------------------
// Stop EIA reception of a packet over the line represented by the LCB.
// This procedure is called by EIAProcess when it detects a dead line.
[
DisableInterrupts()
//Put the line in throw-away state.
let eiaLTE = lv eiaLT>>EIALT.eiaLTE↑(lcb>>LCB.line)

//Put the line in throw-away state, then
//remove the EIALCB from the EIALTE, then
//put the line back into bisync input state.
eiaLTE>>EIALTE.iState = stateThrowAway
eiaLTE>>EIALTE.iLCB = 0
eiaLTE>>EIALTE.iState = stateBiSyncInput

EnableInterrupts()
]

//----------------------------------------------------------------------------
and StartEIAT(lcb) be
//----------------------------------------------------------------------------
// Start EIA transmission of a packet.
[
DisableInterrupts()
let eiaLCB = lcb>>LCB.oEIALCB

//Set up to output from oPBI.
eiaLCB>>EIALCB.byteCount = lcb>>LCB.oPBI>>PBI.packetLength
eiaLCB>>EIALCB.bytePointer = lv (lcb>>LCB.oPBI)>>EIAPBI.type
eiaLCB>>EIALCB.firmStatus = 0
eiaLCB>>EIALCB.hardStatus = 0
eiaLCB>>EIALCB.partialCRC = 0
eiaLT>>EIALT.eiaLTE↑(lcb>>LCB.line).oLCB = eiaLCB

//Inform the EIA interface board that there is something new to do.
@eiaControl = swi % (lcb>>LCB.line lshift 9)
EnableInterrupts()
]

//----------------------------------------------------------------------------
and StopEIAT(lcb) be
//----------------------------------------------------------------------------
// Disable EIA transmission of a packet.
// It is safe to call from both interrupt and non interrupt level.
[
DisableInterrupts()
let eiaLTE = lv eiaLT>>EIALT.eiaLTE↑(lcb>>LCB.line)

//Put the line in throw-away state, then
//remove the EIALCB from the EIALTE, then
//put the line back into BiSync output state.
eiaLTE>>EIALTE.oState = stateThrowAway
eiaLTE>>EIALTE.oLCB = 0
eiaLTE>>EIALTE.oState = stateBiSyncOutput

EnableInterrupts()
]