// PupAlComProca.bcpl - PUP level -1 driver for ComProc
// Copyright Xerox Corporation 1979

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

get "Pup0.decl"
get "PupAlComProc.decl"

external
[
// outgoing procedures
CPFinishProc; CPSwatContextProc; CPInterrupt
StartCPT; StopCPT; StartCPR; StopCPR

// incoming procedures
CPOutputDone; CPInputDone
Enqueue; Dequeue
DisableInterrupts; EnableInterrupts; DestroyInterrupt

// incoming statics
pbiFreeQ; lenPup; cpNDB; cpLT
savedCPFinishProc; lvUserFinishProc; lvSwatContextProc
]

static savedCPSwatProc

//----------------------------------------------------------------------------
let CPFinishProc() be
//----------------------------------------------------------------------------
[
let mask = 0
for line = 0 to maxLine do
   [
   (table [ mcChangeControlReg; 1401b ])(4*line, 300b) //rcvEnbl, sndEnbl
   if cpLT>>CPLT.cpLTE↑line.exists then
      [
      cpLT>>CPLT.cpLTE↑line.iState = stateThrowAway
      cpLT>>CPLT.cpLTE↑line.oState = stateThrowAway
      mask = cpNDB>>CPNDB.lcb↑line.iCPLCB>>CPLCB.intMask
      ]
   ]
DestroyInterrupt(mask)
@lvSwatContextProc = savedCPSwatProc
@lvUserFinishProc = savedCPFinishProc
]

//----------------------------------------------------------------------------
and CPSwatContextProc() be
//----------------------------------------------------------------------------
[
savedCPSwatProc = @lvSwatContextProc
@lvSwatContextProc = table
   [
   #024413	// lda 1 .+13		; lineInhibit lshift 1
   #101005	// mov 0 0 snr		; skip if leaving swat
   #125241	//  movor 1 1 skp	; turn on line inhibit
   #125220	//  movzr 1 1		; turn off line inhibit
   #020410	// lda 0 .+10		; maxLine * 4
   #030410	// lda 2 .+10		; 1 * 4
   #065400	// changeControlReg
   #101005	// mov 0 0 snr
   #001401	//  jmp 1 3
   #142400	// sub 2 0
   #000774	// jmp .-4
   #001000	// line inhibit lshift 1
   #000074	// maxLine * 4
   #000004	// 1 * 4
   ]
]

//----------------------------------------------------------------------------
and CPInterrupt() be
//----------------------------------------------------------------------------
// Control comes here when the ComProc microcode interrupts.
[
for line = 0 to maxLine do if cpLT>>CPLT.cpLTE↑line.exists then
   [
   let lcb = lv cpNDB>>CPNDB.lcb↑line

   //Check input LCBs.
   let cpLCB = lcb>>LCB.iCPLCB
   let firmStatus = cpLCB>>CPLCB.firmStatus
   if firmStatus ls 0 then
      [
      //Dont look here again for a completed CPLCB
      cpLCB>>CPLCB.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) - (cpLCB>>CPLCB.byteCount & 77777B)
            CPInputDone(lcb)
            endcase
            ]
         case errorFatal:
            [
            StopCPR(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 StartCPR(lcb)
      ]

//CPInterrupt (cont'd)

   //check output LCBs.
   cpLCB = lcb>>LCB.oCPLCB
   firmStatus = cpLCB>>CPLCB.firmStatus
   if firmStatus ls 0 then
      [
      //Dont look here again for a completed CPLCB
      cpLCB>>CPLCB.firmStatus = 0

      //Take care of any errors that might have occured.
      switchon (firmStatus & 77777B) into
         [
         case errorFatal: StopCPT(lcb)  //fall through
         case errorNone:
            [
            CPOutputDone(lcb)
            endcase
            ]
         default: StartCPT(lcb)
         ]
      ]
   ]
]

//----------------------------------------------------------------------------
and StartCPR(lcb) be
//----------------------------------------------------------------------------
// Start ComProc reception of a packet over the line represented by the LCB.
// This procedure is called by InitAltoComProc to start things up,
// by CPInterrupt when an input is complete to restart reception, and
// by CPProcess to restart reception on a line that ran out of PBIs.
[
DisableInterrupts()
let cpLCB = lcb>>LCB.iCPLCB

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

//Link the CPLCB to the line's LTE.
//The microcode is always watching for this to go non-zero.
cpLT>>CPLT.cpLTE↑(lcb>>LCB.line).iLCB = cpLCB
EnableInterrupts()
]

//----------------------------------------------------------------------------
and StopCPR(lcb) be
//----------------------------------------------------------------------------
// Stop ComProc reception of a packet over the line represented by the LCB.
// This procedure is called by CPProcess when it detects a dead line.
[
DisableInterrupts()
//Put the line in throw-away state.
let cpLTE = lv cpLT>>CPLT.cpLTE↑(lcb>>LCB.line)

//Put the line in throw-away state, then
//remove the CPLCB from the CPLTE, then
//put the line back into BiSync input state.
cpLTE>>CPLTE.iState = stateThrowAway
cpLTE>>CPLTE.iLCB = 0
cpLTE>>CPLTE.iState = stateBiSyncInput

EnableInterrupts()
]

//----------------------------------------------------------------------------
and StartCPT(lcb) be
//----------------------------------------------------------------------------
// Start ComProc transmission of a packet.
[
DisableInterrupts()
let cpLCB = lcb>>LCB.oCPLCB

//Set up to output from oPBI.
cpLCB>>CPLCB.byteCount = lcb>>LCB.oPBI>>PBI.packetLength
cpLCB>>CPLCB.bytePointer = lv (lcb>>LCB.oPBI)>>CPPBI.type
cpLCB>>CPLCB.firmStatus = 0
cpLCB>>CPLCB.hardStatus = 0
cpLCB>>CPLCB.partialCRC = 0
cpLT>>CPLT.cpLTE↑(lcb>>LCB.line).oLCB = cpLCB

//Inform the EIA interface board that there is something new to do.
(table [ mcChangeControlReg; 1401b ])(4*lcb>>LCB.line, 100100b)
EnableInterrupts()
]

//----------------------------------------------------------------------------
and StopCPT(lcb) be
//----------------------------------------------------------------------------
// Disable ComProc transmission of a packet.
[
DisableInterrupts()
let cpLTE = lv cpLT>>CPLT.cpLTE↑(lcb>>LCB.line)

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

EnableInterrupts()
]