// PupBSPBlock.bcpl -- procedures for fast BSP transfers
// Copyright Xerox Corporation 1979, 1980
// Last modified December 30, 1980  5:35 PM by Boggs

get "pup.decl"

external
[
// Outgoing procedures
BSPReadBlock; BSPWriteBlock

// Incoming procedures
BSPPrepareIPBI; BSPGetCleanup; BSPPrepareOPBI; BSPForceOutput
ByteBlt; Min; Errors

// Statics
offsetBSPStr
]

structure [ lh byte; rh byte ]


// ---------------------------------------------------------------------------
let BSPReadBlock(str, wordP, byteP, count, timeout; numargs na)= valof
// ---------------------------------------------------------------------------
// Read a maximum of count bytes from the BSP stream str,
// storing them starting at address wordP in byte byteP (0=left,
// 1=right half).  timeout (optional) is defined as for BSPGetByte.
// Returns the actual number of bytes read.
[
let soc = str-offsetBSPStr
let bytesSoFar = 0
while count gr 0 do
   [
   // Ensure there is at least one byte to read, getting new iPBI if necessary
   let ec = BSPPrepareIPBI(soc, (na ge 5? timeout, -1))
   if ec ne 0 then [ Errors(str, ec); break ]

   // Transfer as many bytes as we can
   let c = Min(str>>BSPStr.iByteC, count)
   ByteBlt(wordP, byteP, str>>BSPStr.iWordP, str>>BSPStr.iByteP, c)

   // Adjust counts and pointers to account for bytes just transferred
   str>>BSPStr.iWordP = str>>BSPStr.iWordP + (c+str>>BSPStr.iByteP) rshift 1
   str>>BSPStr.iByteP = (c+str>>BSPStr.iByteP) & 1
   str>>BSPStr.iByteC = str>>BSPStr.iByteC - c
   wordP = wordP+(c+byteP) rshift 1
   byteP = (c+byteP) & 1
   bytesSoFar = bytesSoFar+c
   count = count-c

   // Clean up stream if current iPBI is exhausted
   if str>>BSPStr.iByteC eq 0 then BSPGetCleanup(soc)
   ]
resultis bytesSoFar
]

// ---------------------------------------------------------------------------
and BSPWriteBlock(str, wordP, byteP, count, timeout; numargs na)= valof
// ---------------------------------------------------------------------------
// Write a maximum of count bytes into the BSP stream str, getting
// them starting at address wordP in byte byteP (0=left,
// 1=right half).  timeout (optional) is defined as for BSPPutByte.
// Returns the actual number of bytes written.
[
let soc = str-offsetBSPStr
let bytesSoFar = 0
while count gr 0 do
   [
   // Ensure there is an oPBI set up
   let ec = BSPPrepareOPBI(soc, (na ge 5? timeout, -1))
   if ec ne 0 then [ Errors(str, ec); break ]

   // Transfer as many bytes as we can
   let c = Min(str>>BSPStr.oByteC, count)
   ByteBlt(str>>BSPStr.oWordP, str>>BSPStr.oByteP, wordP, byteP, c)

   // Adjust counts and pointers to account for bytes just transferred
   str>>BSPStr.oWordP = str>>BSPStr.oWordP + (c+str>>BSPStr.oByteP) rshift 1
   str>>BSPStr.oByteP = (c+str>>BSPStr.oByteP) & 1
   str>>BSPStr.oByteC = str>>BSPStr.oByteC - c
   wordP = wordP+(c+byteP) rshift 1
   byteP = (c+byteP) & 1
   bytesSoFar = bytesSoFar+c
   count = count-c

   // Ensure that if the last byte transferred was to the left half, the
   // right half is zero.  n.b. this may clobber one word beyond the end
   // of the data portion of the Pup, but that's the checksum word, so ok.
   str>>BSPStr.oWordP>>rh = 0

   // Clean up stream if current oPBI is full
   if str>>BSPStr.oByteC eq 0 then BSPForceOutput(soc)
   ]
resultis bytesSoFar
]