Ring Buffer Routines




This  package  consists  of  a  set  of  fairly  fast assembly-language
procedures  for  buffering  data by  means  of  circular  buffers.  The
package comes  in two  versions: a  "byte" version  (RingBytes.br) that
deals with  bytes and  packs them two  per word,  and a  "word" version
(RingWords.br) that deals with  full words.  The procedures in  the two
packages  are  called identically,  so  one may  substitute  the "word"
version for the "byte" version to  gain about a factor of two  in speed
at the cost of using buffer space only half as efficiently.  The binary
files  mentioned above  are contained  in RingBuffer.dm,  and the
source files are in RingBuffer.dm.  A Nova version  of this
package is available.

A ring buffer is described by a Ring Buffer Descriptor (RBD),  which is
the  address  of  a  4-word  patch  of  memory  provided  by  the user,
initialized through a call to InitRingBuffer, and thereafter maintained
by the routines in the package.  The "byte" and "word" versions  of the
routines make different uses of the RBD, but this is of no  interest to
callers.

InitRingBuffer(RBD,Buffer,Length)
    Initializes  the RBD  to describe  a block  of storage  starting at
    "Buffer" and of length "Length" (in words).

ResetRingBuffer(RBD)
    Renders the ring buffer described by RBD empty.

RingBufferEmpty(RBD) = true or false
    Returns true if the buffer is empty.

RingBufferFull(RBD) = true or false
    Returns true if the buffer is full.

ReadRingBuffer(RBD) = Item (byte or word)
    Returns the next Item in the ring buffer if there is one, or  -1 if
    there isn't.  Obviously,  if the "word"  version of the  package is
    being used and -1 is a possible Item, then the caller  should check
    with RingBufferEmpty before calling ReadRingBuffer.

WriteRingBuffer(RBD,Item) = true or false
    Attempts  to put  Item into  the ring  buffer and  returns  true if
    successful.  The  "byte" version of  this procedure depends  on the
    left half of Item being zero.

When these routines are used to pass streams of data between interrupt-
level and non-interrupt-level code, the following precautions should be
observed to avoid races:

1.  For a given RBD, neither ReadRingBuffer nor  WriteRingBuffer should
be  called  both from  interrupt  level and  from  non-interrupt level.
However,  ReadRingBuffer  may  be  called  from  interrupt   level  and
WriteRingBuffer from non-interrupt level or vice versa.


                             ------------
                   Copyright Xerox Corporation 1979


Ring Buffer Routines       February 20, 1976                          2




2.   InitRingBuffer  and  ResetRingBuffer  should  not  be  called from
interrupt level.

3.  Calls to all routines should be made with interrupts on, since some
of them execute "dir" and "eir" internally.  (This is not a  problem if
the BCPL Interrupt Package is being used.)

The following information is provided for debugging purposes  only, and
one should not write code that depends on it.

The "byte"  version of the  package lays out  the RBD in  the following
way:

    structure RBD: [
        Begin word      // Pointer to start of buffer
        Length word     // Buffer size in bytes
        Read word       // Current read index
        Write word      // Current write index
        ]

The buffer is treated  as an array of  bytes, packed left to  right and
indexed starting at zero.  The Read and Write indices refer to the last
byte read or written.

The "word" version of the package uses the RBD in this way:

    structure RBD: [
        Begin word      // Pointer to start of buffer
        End word        // Pointer past end of buffer
        Read word       // Current read pointer
        Write word      // Current write pointer
        ]

The End word  points to the  first word beyond  the end of  the buffer;
i.e. its value is  Begin plus the length  of the buffer.  The  Read and
Write pointers point to the next word to be read or written.

Rough timings for the  important procedures are now given.   The counts
are  simply  number   of  instructions  executed,  not   including  the
instruction that called the procedure.

                             "byte"              "word"
    RingBufferEmpty          9                   9
    RingBufferFull           10                  11
    ReadRingBuffer           20.5 normally       12 normally
                             9 if empty          9 if empty
    WriteRingBuffer          25 normally         13 normally
                             13 if full          13 if full