Implementing the non-blocking pipes API

From: Per Bojsen <bojsen_at_.....>
Date: Thu Mar 09 2006 - 06:56:49 PST
Hi,

in order to help the process of refining the pipes API along and to
improve the understanding of the semantics of the pipes API, I sat
down for a few hours and created a crude implementation of the
nob-blocking subset of the pipes API for DPI enabled simulators
based on John's latest distribution of 2/24/06.  I have enclosed the
current state of this implementation.  Some caveats:

  1) The implementation is not meant to be product grade.  It is a
     toy but is sufficiently rich to allow experimentation with the
     pipes API.

  2) No attempt has been made to make the implementation efficient.
     The goal was not performance but quick and simple implementation.

  3) The code has only been lightly tested.  I have not yet tested
     it with a simulator.  The enclosed test is C only.

  4) The implementation is based on my current understanding of the
     API and its semantics which is undoubtedly wrong in some areas.
     See below.

Note, it is fairly trivial to extend the implementation to include
the blocking API.  I think John has an example of how to implement
the blocking API for SystemC.  This should be usable with my
implementation of the non-blocking API bugs in the implementation
notwithstanding.

On my quest to implement the non-blocking API I encountered a
number of areas where I was unsure about the semantics of the API.
Here are some questions that was generated as a result of this:

  a) There are no calls on the C side to create a pipe.  Pipes are
     `created' from the HDL side?

  b) The description of dpi_pipe_c_try_receive() states that no data
     is transferred unless at least the indicated number of elements
     exist in the pipe.  However, the method also has the
     num_elements_read argument which seems to indicate it is possible
     to receive less than what was asked for.  I assume this comes
     into play during flushing, i.e., when a pipe is being flushed,
     the try_receive() calls may return less than what was requested,
     correct?

  c) In the dpi_pipe_c_try_receive(), is it the user's responsibility
     to ensure the memory area pointed to by data is large enough to
     receive the data requested?  Similarly for
     dpi_pipe_hdl_try_receive(), dpi_pipe_c_try_send(), and
     dpi_pipe_hdl_try_send().

  d) How are elements packed in the data array?  Are they byte packed
     or svBitVecVal (i.e., 32-bit word) packed?

  e) In dpi_pipe_c_try_receive() when flushing is going on, it is
     assume that fewer elements than requested may be returned.  What
     happens if the number of bytes currently in the buffer is not a
     multiple of the element size?  Will a partial element be returned
     or will the last few bytes (less than bytes_per_element) be left
     in the buffer despite flushing being in effect?

  f) In dpi_pipe_c_try_receive() and dpi_pipe_hdl_try_receive(), what
     is num_elements_read set to if no data transfer happens?  Is it
     set to 0 or is it not set at all?

  g) EOMs can coalesce if the consumer asks for a large enough chunk
     of data that will contain 2 or more messages sent by the producer
     with EOMs set.  Is this correct?

  h) Are input and output pipes fully symmetric?  Can they be
     implemented with shared try_send() and try_receive() functions?

  i) Message size limit: I think we decided to make it unlimited.
     This requires the implementation to dynamically resize buffering
     at least on the software side, correct?

  j) What are the exact conditions for calling the notify callback?

Since I didn't have the answers to the above questions I had to make
some assumptions during implementation:

  A1) Input and output pipes are symmetric.  They are
      implemented with shared try_send() and try_receive() functions.

  A2) EOM acts like a flag on the last byte of the
      message.  On the consumer side, whenever this byte is part of the
      data consumed EOM will be true.

  A3) num_bytes_read is set to 0 when no data transfer happens.

  A4) When the number of bytes available in a buffer is not a multiple
      of the element size and flushing is in progress and
      dpi_pipe_c_try_receive() is asking for more data than available,
      then the last element returned will be partial.  Otherwise the
      buffer will not flush completely.

  A5) Bytes are packed in svBitVecVal words in a little endian manner.
      Elements are byte packed both within calls and between calls.

  A6) No error checking is done on pipe context before creating pipes.

  A7) The notify callback is called on successful transfer of data and
      successfull flushing.

Some known issues exist:

  * Limitation: Currently, the buffer size is fixed and prevents any
    message larger than the buffer size to be sent.

  * Potential bug: The EOM handling does not look right in the output
    of the PipesNBTest1 test.  It looks like EOM is set on the first
    message received from the pipe rather than the last or perhaps
    some in the middle.  Add some code to track where we should expect
    to see EOM.

Also, I think assumption A7 is wrong.  I think you actually want
the callback to happen when blocking is required, rather than
when data is transferred.

There are some makefiles included with the code that are trivial
and should be easy to modify to your environment.  You will need
John's dpi_pipes.h include file to compile.  Also, I included
a stripped down version of svdpi.h and a dummy implementation of
svGetScope() and svSetScope() to allow testing without a
simulator.  If you want to use the code with a simulator you must
exclude these from the library and point to the svdpi.h supplied
with the simulator.

Please keep the caveats in mind when using this code.  Neither
Zaiq nor I are responsible for any mishaps that may occur due to
using this code :-)

Have fun,
Per



Received on Thu Mar 9 06:57:03 2006

This archive was generated by hypermail 2.1.8 : Thu Mar 09 2006 - 06:57:22 PST