updates to pipes proposal: merging of of fifo and pipe interfaces into unified pipe interface

From: John Stickley <john_stickley_at_.....>
Date: Tue Feb 21 2006 - 09:48:54 PST
Greetings ITC Techies,

As a follow up to the face-to-face two weeks ago, I've been
busy incorporating some of the good suggestions at that
meeting.

One major thing I heard was some disappointment that the non-blocking
fifo interface was not congruent with the pipes interface
in terms of handling data shaping, variable length messaging.

Initially I had thought there were some complications with
combining data shaping in non-blocking interfaces. However,
the more I thought about it the more I realized that we can
probably have our cake and eat it too.

Plus I agree that unifying the two would remove the complication
of two separate use models - one for TLM/FIFO applications and
the other for streaming/PIPE applications. We can still have
two use models but at least a unified interface.

Toward that end, I've made some improvements to the current
proposal and have been able to qualify these in the prototype.

Here is a summary of the changes:

1. Merging of FIFO and PIPE interfaces

    I've merged dpi_fifo non-blocking calls into dpi_pipe calls.
    Now the dpi_pipe interface supports the full blocking streaming
    calls and data shaping features just as it had before.

    Plus it now has a thread-neutral non-blocking interface as
    well. The non-blocking send() and receive() calls take
    the same argument profiles as the blocking ones so that
    data shaping is still supported.

----------------------------------------------------
Blocking (thread-aware calls):

----------------
C side

Data transfer ops:
   dpi_pipe_c_send()
   dpi_pipe_c_receive()
   dpi_pipe_c_flush()

----------------
HDL side

Data transfer ops:
   dpi_pipe_hdl_send()
   dpi_pipe_hdl_receive()
   dpi_pipe_hdl_flush()

----------------------------------------------------
Non-blocking (thread-neutral calls):

----------------
C side

Data transfer ops:
   dpi_pipe_c_try_send()
   dpi_pipe_c_try_receive()
   dpi_pipe_c_try_flush()

Query ops:
   dpi_pipe_c_can_send()
   dpi_pipe_c_can_receive()

Notify ops:
   (dpi_pipe_notify_ok_to_send)()
   (dpi_pipe_notify_ok_to_receive)()

----------------
HDL side

Data transfer ops:
   dpi_pipe_hdl_try_send()
   dpi_pipe_hdl_try_receive()
   dpi_pipe_hdl_try_flush()

Query ops:
   dpi_pipe_hdl_can_send()
   dpi_pipe_hdl_can_receive()

Notify ops:
   dpi_pipe_hdl_notify_ok_to_send()
   dpi_pipe_hdl_notify_ok_to_receive()

2. Notify callbacks now dynamic on the C side

    Per had commented at the face-to-face that
    the notify callbacks were hard coded function names and
    questioned if we should make them function pointers
    instead. After exploring this more, it became clear
    that the fixed named callbacks do not allow much
    flexibility in terms of implementing higher thread-aware
    interfaces on top of the thread-neutral calls. For example
    you might want one function if you're using TLM proxies
    but another if you're using blocking DPI ops directly.
    To accommodate this, it turns out to be a lot more flexible
    if the notify callback can be changed to different functions
    on a pipe by pipe basis. For this reason I've changed
    the notify callback to be programmable on the C side.

    User's will never really need to deal with these complications
    since they will tend to use higher level blocking calls
    or TLM interfaces. So this is a complication that can be
    potentially limited to the implementor not the user.
    Nonetheless I think it makes sense to make the underlying
    API a clear part of the standard for the implementor.

    To support the programmable notify callbacks two
    functions were added to set a callback pointer and
    context and to retrieve context:

    typedef void (*dpi_pipe_notify_callback)(
      void *context );      // input: C model context

    void *dpi_pipe_get_notify_context(
      void *pipe_handle );  // input: pipe handle

    void dpi_pipe_set_notify_callback(
      void *pipe_handle,  // input: pipe handle
      dpi_pipe_notify_callback notify_callback,
                          // input: notify callback function
      void *notify_context ); // input: notify context


    The notify callback itself is now passed the context
    directly which is more efficient (no longer has to do a
    lookup using svGetScope()/svGetUserData()).

    The attached examples show how these calls are used.

3. Pipe handles used in place of pipe IDs on the C side

    Another comment that was made a few weeks ago is that
    it is somewhat awkward to set the scope before each
    call to a pipe on the C side. It turns out, this requirement
    also can make implementations less efficient.

    I'm now proposing that we replace the pipe-id argument
    to all C-side calls with a pipe_handle argument instead.
    The pipe handle can be derived once at initialization time
    and reused many times without having to set scope each
    time and requiring the internal implementation to do a
    lookup based on the scope and the pipe ID to retrieve
    the internal data structure associated with a pipe.

    Doing this not only made the user application code a
    lot cleaner looking but made the implementation more
    efficient as well (fewer lookups and pointer
    indirections on each call).

    To faciliate pipe handles, a new call is added to
    retrieve a pipe handle for a given DPI scope and
    pipe ID:

    void *dpi_pipe_c_handle(   // return: pipe handle
      svScope hdl_context,     // input: HDL context
      int pipe_id,             // input: intra-module pipe identifier
      svBit input_or_output ); // input: 1 for input pipe,
                               //        0 for output pipe

4. Thread-neutral calls to support blocking flush op

    We may want to re-think this a bit but this is what
    I have for now. Since flush is, by definition, a blocking
    operation, it is thread-aware. To be consistent with
    providing thread-neutral API support for implementation
    of all blocking calls, it stands to reason we need
    dpi_c/hdl_try_flush() calls to compliment the
    dpi_c/hdl_flush() calls. So I've added this to the API.
    There are a couple of other possible options for this.

5. Automatic flush-on-eom

    Cadence suggested that, on a pipe-by-pipe basis, that
    there be a means to enable automatic flush when eom is
    specified. The committee agreed that this would be
    useful.

    A new call is added  to specify automatic flush-on-eom
    mode for a pipe designated by a given handle. This mode
    configuration call is always initiated only on the C side
    (at initialization) for both input and output pipes:

    void dpi_pipe_set_eom_auto_flush(
      void *pipe_handle,  // input: pipe handle
      svBit enabled );    // input: enable/disable

6. Limitless transaction sizes on the C side for data shaping

    At the face-to-face Shabtay expressed some disappointment
    that for data shaping funnels, the input transaction from
    the C side is limited in size to the width of the pipe as
    statically specified on the HDL side.

    Happily it turns out this is not true !

    Since svBitVecVal arrays can be essentially unbounded, using
    data shaping (funnel) an arbitrarily large number of elements
    can be sent from or received to the C side in a single call.

    Only on the HDL side do we have a practical limitation on the
    number of elements that can be received or sent on any given
    call. As before, this is equal to the size of the statically
    declared data arguments on the HDL side.

I've attached header files for the new calls for both the HDL
and C sides.

I've attached a simple example of blocking call implementations
for both the C and HDL side using the thread-neutral interfaces
described above. (For HDL side example see dpi_pipes.vh, for
C side example see dpi_pipes_sysc.cxx).

I've also attached the revised example of the TLM proxy
model that is currently in the appendix of the working
document.

I'm ready to make these detailed updates to the working document
but I want to make sure I have some degree of buyin. I can also
update the distributed example to reflect the latest changes.

I really think with this proposal I've addressed many of the
concerns raised about pipes at the face-to-face and, with the
committee's cooperation, I'd like incorporate these changes into
the working document ASAP.

-- johnS

This email may contain material that is confidential, privileged
and/or attorney work product for the sole use of the intended
recipient.  Any review, reliance or distribution by others or
forwarding without express permission        /\
is strictly prohibited. If you are     /\   |  \
not the intended recipient please     |  \ /   |
contact the sender and delete        /    \     \
all copies.                      /\_/  K2  \_    \_
______________________________/\/            \     \
John Stickley                   \             \     \
Principal Engineer               \             \________________
Mentor Graphics - MED             \_
17 E. Cedar Place                   \   john_stickley@mentor.com
Ramsey, NJ  07446                    \     Phone: (201) 818-2585
________________________________________________________________

//===========================================================================
// dpi_pipes.h
//
// @(#) $Id: dpi_pipes.h,v 1.5 2005/10/03 16:38:30 jstickle Exp $
//===========================================================================

//---------------------------------------------------------------------------
//   Mentor Graphics, Corp.
//
//   (C) Copyright, Mentor Graphics, Corp. 2003-2006
//   All Rights Reserved
//   Licensed Materials - Property of Mentor Graphics, Corp.
//
//   No part of this file may be reproduced, stored in a retrieval system,
//   or transmitted in any form or by any means --- electronic, mechanical,
//   photocopying, recording, or otherwise --- without prior written permission
//   of Mentor Graphics, Corp.
//
//   WARRANTY:
//   Use all material in this file at your own risk.  Mentor Graphics, Corp.
//   makes no claims about any material contained in this file.
//---------------------------------------------------------------------------

#ifndef _dpi_pipes_h
#define _dpi_pipes_h

#include "svdpi.h"

#ifdef __cplusplus
extern "C" {
#endif

//---------------------------------------------------------------------------
// dpi_pipe_c_handle()                                       -- johnS 1-26-06
//
// This function retreives an opaque handle representing a transaction
// input or output pipe given an HDL scope and a pipe ID.
//---------------------------------------------------------------------------

void *dpi_pipe_c_handle(
    svScope hdl_context,     // input: HDL context
    int pipe_id,             // input: intra-module pipe identifier
    svBit input_or_output ); // input: 1 for input pipe, 0 for output pipe

//---------------------------------------------------------------------------
// dpi_pipe_c_send()                                         -- johnS 1-26-06
//
// These is the basic blocking send function for a transaction input pipe.
// The passed in data is sent to the pipe. If necessary the calling thread
// is suspended until there is room in the pipe.
//
// The eom arg is a flag which is used for user specified end-of-message (eom)
// indication. It can be used for example to mark the end of a frame containing
// a sequence of transactions.
//
// dpi_pipe_c_receive()
//
// This is the basic blocking receive function for a transaction output pipe.
//
// The eom argument for this call is an output argument. It is set to the
// same settings of the flag passed on the send end of the pipe as described
// above. Thus is can be used by the caller to query whether the current
// read is one for which an eom was specified when the data was written on
// the send end.
//
// Both the send() and receive() calls are thread-aware. They can be
// easily implemented using a simple reference implementation that makes
// use of the non-blocking thread-neutral interface decribed below
// in conjunction with a selected threading system.
//---------------------------------------------------------------------------

void dpi_pipe_c_send(
    void *pipe_handle,       // input: pipe handle
    int bytes_per_element,   // input: #bits/element
    int num_elements,        // input: #elements to be written
    const svBitVecVal *data, // input: data
    svBit eom );             // input: end-of-message marker flag (and flush)

void dpi_pipe_c_receive(
    void *pipe_handle,       // input: pipe handle
    int bytes_per_element,   // input: #bits/element
    int num_elements,        // input: #elements to be read
    int *num_elements_read,  // output: #elements actually read
    svBitVecVal *data,       // output: data
    svBit *eom );            // output: end-of-message marker flag (and flush)

//---------------------------------------------------------------------------
// dpi_pipe_c_flush()                                        -- johnS 1-26-06
//
// Flush pipelined data.
//---------------------------------------------------------------------------

void dpi_pipe_c_flush(
    void *pipe_handle );    // input: pipe handle

//---------------------------------------------------------------------------
// dpi_pipe_c_try_send()                                     -- johnS 1-26-06
//
// This is the basic non-blocking send function for a transaction input pipe.
// If there is room in the pipe for the indicated number of elements, the
// data is transferred to the pipe and a success status of 1 is returned.
// Otherwise, nothing is done with the data and a status of 0 is returned.
//
// This function is thread-neutral can can be used to create a reference
// implementation of the blocking send function (dpi_pipe_c_send)
// over a selected C-based threading environment.
//
// dpi_pipe_c_try_receive()
//
// This is the basic non-blocking receive function for a transaction output
// pipe. If the indicated number of elements exist in the pipe, the data is
// transferred out of the pipe and a success status of 1 is returned.
// Otherwise, the data in the pipe is left alone and a status of 0 is returned.
//
// This function is thread-neutral can can be used to create a reference
// implementation of the blocking receive function (dpi_pipe_c_receive)
// over a selected C-based threading environment.
//
//---------------------------------------------------------------------------

int dpi_pipe_c_try_send(
    void *pipe_handle,       // input: pipe handle
    int bytes_per_element,   // input: #bits/element
    int num_elements,        // input: #elements to be written
    const svBitVecVal *data, // input: data
    svBit eom );             // input: end-of-message marker flag

int dpi_pipe_c_try_receive(
    void *pipe_handle,      // input: pipe handle
    int bytes_per_element,  // input: #bits/element
    int num_elements,       // input: #elements to be read
    int *num_elements_read, // output: #elements actually read
    svBitVecVal *data,      // output: data
    svBit *eom );           // output: end-of-message marker flag

//---------------------------------------------------------------------------
// dpi_pipe_c_try_flush()                                       johnS 1-26-06
//---------------------------------------------------------------------------

int dpi_pipe_c_try_flush(
    void *pipe_handle );     // input: pipe handle

//---------------------------------------------------------------------------
// dpi_pipe_c_can_send()                                     -- johnS 1-26-06
//
// This is function indicates if there is currently space in the pipe
// for the indicated number of elements meaning that the next call to
// dpi_pipe_c_send() will succeed without requiring a block.
//
// dpi_pipe_c_can_receive()
//
// This is function indicates if there is currently at least the indicated
// number of elements in the pipe meaning that the next call to
// dpi_pipe_c_receive() will succeed without requiring a block.
//
// For both of these calls, a return value 0 indicates that the operation
// cannot succeed, 1 indicates that it can succeed.
//---------------------------------------------------------------------------

int dpi_pipe_c_can_send(
    void *pipe_handle,      // input: pipe handle
    int bytes_per_element,  // input: #bits/element
    int num_elements );     // input: #elements to be written

int dpi_pipe_c_can_receive(
    void *pipe_handle,      // input: pipe handle
    int bytes_per_element,  // input: #bits/element
    int num_elements );     // input: #elements to be written

//---------------------------------------------------------------------------
// Notify callback support                                   -- johnS 2-15-06
//

typedef void (*dpi_pipe_notify_callback)(
    void *context );       // input: C model context

void *dpi_pipe_get_notify_context(
    void *pipe_handle );    // input: pipe handle

void dpi_pipe_set_notify_callback(
    void *pipe_handle,      // input: pipe handle
    dpi_pipe_notify_callback notify_callback,
                            // input: notify callback function
    void *notify_context ); // input: notify context

//---------------------------------------------------------------------------
// EOM auto-flush support                                    -- johnS 2-15-06
//

void dpi_pipe_set_eom_auto_flush(
     void *pipe_handle,  // input: pipe handle
     svBit enabled );    // input: enable/disable

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif // _dpi_pipes_h

// @(#) $Id: dpi_pipes.vh,v 1.3 2006/02/21 04:20:06 jstickle Exp $
 
//---------------------------------------------------------------------------
//   Mentor Graphics, Corp.
//
//   (C) Copyright, Mentor Graphics, Corp. 2003-2006
//   All Rights Reserved
//   Licensed Materials - Property of Mentor Graphics, Corp.
//
//   No part of this file may be reproduced, stored in a retrieval system,
//   or transmitted in any form or by any means --- electronic, mechanical,
//   photocopying, recording, or otherwise --- without prior written permission
//   of Mentor Graphics, Corp.
//
//   WARRANTY:
//   Use all material in this file at your own risk.  Mentor Graphics, Corp.
//   makes no claims about any material contained in this file.
//---------------------------------------------------------------------------

`ifdef DPI_PIPE_MAX_BITS
`else
`define DPI_PIPE_MAX_BITS 512
`endif

`ifdef DPI_PIPE_MAX_CHANNELS
`else
`define DPI_PIPE_MAX_CHANNELS 32
`endif

reg [`DPI_PIPE_MAX_CHANNELS-1:0] ok_to_receive;
reg [`DPI_PIPE_MAX_CHANNELS-1:0] ok_to_send;

initial ok_to_receive = 0;
initial ok_to_send = 0;

//===========================================================================
// dpi_pipe_hdl_try_receive()                                   johnS 9-15-05
// dpi_pipe_hdl_try_send()
//
// Non-blocking send/receive to pipe channel from HDL endpoint.
//===========================================================================

import "DPI-C" function int dpi_pipe_hdl_try_receive(
    input  int pipe_id,             // input: intra-module pipe identifier
    input  int bytes_per_element,   // input: #bytes/element
    input  int num_elements,        // input: #elements to be read
    output int num_elements_read,   // output: #elements actually read
    output bit [`DPI_PIPE_MAX_BITS-1:0] data, // output: data
    output bit eom );               // output: end-of-message marker flag

import "DPI-C" function int dpi_pipe_hdl_try_send(
    input int pipe_id,           // input: intra-module pipe identifier
    input int bytes_per_element, // input: #bytes/element
    input int num_elements,      // input: #elements to be written
    input bit [`DPI_PIPE_MAX_BITS-1:0] data, // input: data
    input bit eom );             // input: end-of-message marker flag

//===========================================================================
// dpi_pipe_hdl_notify_ok_to_receive()                          johnS 9-15-05
// dpi_pipe_hdl_notify_ok_to_send()
//
// Exported functions to set "OK to send/receive" events from SystemC layer.
//===========================================================================

export "DPI-C" function dpi_pipe_hdl_notify_ok_to_receive;
function void dpi_pipe_hdl_notify_ok_to_receive( int pipe_id );
    begin ok_to_receive[pipe_id] = 1; end
endfunction

export "DPI-C" function dpi_pipe_hdl_notify_ok_to_send;
function void dpi_pipe_hdl_notify_ok_to_send( int pipe_id );
    begin ok_to_send[pipe_id] = 1; end
endfunction

//===========================================================================
// dpi_pipe_hdl_receive()                                       johnS 9-15-05
// dpi_pipe_hdl_send()
//
// Blocking receive/send to pipe channel from HDL endpoint.
//===========================================================================

task dpi_pipe_hdl_receive(
    input  int pipe_id,             // input: intra-module pipe identifier
    input  int bytes_per_element,   // input: #bytes/element
    input  int num_elements,        // input: #elements to be read
    output int num_elements_read,   // output: #elements actually read
    output bit [`DPI_PIPE_MAX_BITS-1:0] data, // output: data
    output bit eom );               // output: end-of-message marker flag

    while( !dpi_pipe_hdl_try_receive( pipe_id,
            bytes_per_element, num_elements, num_elements_read,
            data, eom ) ) begin
        ok_to_receive[pipe_id] = 0;
        wait( ok_to_receive[pipe_id] );
    end
endtask

task dpi_pipe_hdl_send(
    input int pipe_id,           // input: intra-module pipe identifier
    input int bytes_per_element, // input: #bytes/element
    input int num_elements,      // input: #elements to be written
    input bit [`DPI_PIPE_MAX_BITS-1:0] data, // input: data
    input bit eom );             // input: end-of-message marker flag

    while( !dpi_pipe_hdl_try_send( pipe_id,
            bytes_per_element, num_elements, data, eom ) ) begin
        ok_to_send[pipe_id] = 0;
        wait( ok_to_send[pipe_id] );
    end
endtask

//===========================================================================
// dpi_pipe_hdl_flush()                                         johnS 9-15-05
//
// Flush pipelined data
//===========================================================================

import "DPI-C" function int dpi_pipe_hdl_try_flush(
        input int pipe_id );    // input: intra-module pipe identifier

task dpi_pipe_hdl_flush(
    input int pipe_id );         // input: intra-module pipe identifier

    while( !dpi_pipe_hdl_try_flush( pipe_id ) ) begin
        ok_to_send[pipe_id] = 0;
        wait( ok_to_send[pipe_id] );
    end
endtask

//===========================================================================
// dpi_fifos_mti.cxx
//
// @(#) $Id: dpi_pipes_sysc.cxx,v 1.1 2006/02/21 04:20:06 jstickle Exp $
//===========================================================================

//---------------------------------------------------------------------------
//   Mentor Graphics, Corp.
//
//   (C) Copyright, Mentor Graphics, Corp. 2003-2006
//   All Rights Reserved
//   Licensed Materials - Property of Mentor Graphics, Corp.
//
//   No part of this file may be reproduced, stored in a retrieval system,
//   or transmitted in any form or by any means --- electronic, mechanical,
//   photocopying, recording, or otherwise --- without prior written permission
//   of Mentor Graphics, Corp.
//
//   WARRANTY:
//   Use all material in this file at your own risk.  Mentor Graphics, Corp.
//   makes no claims about any material contained in this file.
//---------------------------------------------------------------------------

#include <vector>
#include <systemc.h>
#include "dpi_pipes.h"
#include "svdpi.h"

//---------------------------------------------------------------------------
// notify_ok_to_send_or_receive()                               johnS 2-12-06
//
// This is a callback function that notifies the application that there
// is room for at least 1 data element in an input pipe or least one data
// element in an output pipe.
//
// This callback function assumes it has been given a context object
// that is an sc_event that can be directly posted to.
//---------------------------------------------------------------------------

static void notify_ok_to_send_or_receive(
    void *context ){           // input: notify context
    sc_event *me = (sc_event *)context;
    me->notify();
}

//---------------------------------------------------------------------------
// dpi_pipe_c_send()                                            johnS 1-26-06
//
// This is the basic blocking send function for the C endpoint of a
// transaction input pipe. It first calls the non-blocking send function
// (dpi_pipe_c_try_send()). If it succeeds in sending on the first try,
// it returns happily.
//
// Otherwise continues to wait on an sc_event until there is at least the 
// required number of data elements in the pipe at which point the call
// to dpi_pipe_c_try_send() will succeed.
//---------------------------------------------------------------------------

void dpi_pipe_c_send(
    void *pipe_handle,       // input: pipe handle
    int bytes_per_element,   // input: #bits/element
    int num_elements,        // input: #elements to be written
    const svBitVecVal *data, // input: data
    svBit eom )              // input: end-of-message marker flag
{
    if( !dpi_pipe_c_try_send( pipe_handle,
            bytes_per_element, num_elements, data, eom ) ) {

        sc_event *ok_to_send = (sc_event *)dpi_pipe_get_notify_context(
            pipe_handle );

        // if( notify ok_to_send context has not yet been set up ) ...
        if( ok_to_send == NULL ){
            ok_to_send = new sc_event;
            dpi_pipe_set_notify_callback(
                pipe_handle, notify_ok_to_send_or_receive, ok_to_send );
        }

        while( !dpi_pipe_c_try_send( pipe_handle,
                bytes_per_element, num_elements, data, eom ) )
            wait( *ok_to_send );
    }
}

//---------------------------------------------------------------------------
// dpi_pipe_c_receive()                                         johnS 1-26-06
//
// This is the basic blocking receive function for the C endpoint of a
// transaction output pipe. It first calls the non-blocking receive function
// (dpi_pipe_c_try_receive()). If it succeeds in receiving on the first try,
// it returns happily.
//
// Otherwise continues to wait on an sc_event until there is at least the
// required number of data elements in the pipe at which point the call
// to dpi_pipe_c_try_receive() will succeed.
//---------------------------------------------------------------------------

void dpi_pipe_c_receive(
    void *pipe_handle,      // input: pipe handle
    int bytes_per_element,  // input: #bits/element
    int num_elements,       // input: #elements to be read
    int *num_elements_read, // output: #elements actually read
    svBitVecVal *data,      // output: data
    svBit *eom )            // output: end-of-message marker flag
{
    if( !dpi_pipe_c_try_receive( pipe_handle,
            bytes_per_element, num_elements, num_elements_read, data, eom ) ) {

        sc_event *ok_to_receive = (sc_event *)dpi_pipe_get_notify_context(
            pipe_handle );

        // if( notify ok_to_receive context has not yet been set up ) ...
        if( ok_to_receive == NULL ){
            ok_to_receive = new sc_event;
            dpi_pipe_set_notify_callback(
                pipe_handle, notify_ok_to_send_or_receive, ok_to_receive );
        }

        while( !dpi_pipe_c_try_receive( pipe_handle,
                bytes_per_element, num_elements, num_elements_read,
                data, eom ) )
            wait( *ok_to_receive );
    }
}

//---------------------------------------------------------------------------
// dpi_pipe_c_flush()                                           johnS 1-26-06
//---------------------------------------------------------------------------

void dpi_pipe_c_flush(
    void *pipe_handle )      // input: pipe handle
{
    sc_event *ok_to_send = (sc_event *)dpi_pipe_get_notify_context(
        pipe_handle );

    if( ok_to_send == NULL )
        return;

    while( !dpi_pipe_c_try_flush(pipe_handle) )
        wait( *ok_to_send );
}

//===========================================================================
// pipeline_ingress_proxy.hxx
//
// @(#) $Id: pipeline_ingress_proxy.hxx,v 1.1 2006/02/21 04:09:57 jstickle Exp $
//===========================================================================
 
//---------------------------------------------------------------------------
//   Mentor Graphics, Corp.
//
//   (C) Copyright, Mentor Graphics, Corp. 2003-2006
//   All Rights Reserved
//   Licensed Materials - Property of Mentor Graphics, Corp.
//
//   No part of this file may be reproduced, stored in a retrieval system,
//   or transmitted in any form or by any means --- electronic, mechanical,
//   photocopying, recording, or otherwise --- without prior written permission
//   of Mentor Graphics, Corp.
//
//   WARRANTY:
//   Use all material in this file at your own risk.  Mentor Graphics, Corp.
//   makes no claims about any material contained in this file.
//---------------------------------------------------------------------------
 
#ifndef _pipeline_ingress_proxy_hxx
#define _pipeline_ingress_proxy_hxx

//______________________________                              _______________
// class pipeline_ingress_proxy \____________________________/ johnS 2-5-2006
//
// The pipeline_ingress_proxy module consumes data received over a data channel
// from producer sends it to the Pipeline DUT on the Verilog side by passing
// transactions over a transaction input pipe to the
// PipelineIngressTransactor.
//---------------------------------------------------------------------------

template< typename T, const int NUM_WORDS >
class pipeline_ingress_proxy :
    public sc_module,
    public virtual tlm_put_if<T>
{
  public:
    sc_export< tlm_put_if< T > > put_export;

  private:
    void *m_pipe_handle;
    sc_event m_ok_to_put;

    static void notify_ok_to_put(
            void *context ){           // input: notify context
        sc_event *me = (sc_event *)context;
        me->notify();
    }

    void pack( const T &t, svBitVecVal pipe_data[] );

  public:
     pipeline_ingress_proxy( sc_module_name name,
         const char *transactor_name, int channel )
       : sc_module(name)
    {
        // Bind to channel.
        put_export( *this );

        // Establish binding to transaction input pipe.
        svScope hdl_context = svGetScopeFromName( transactor_name );
        m_pipe_handle = dpi_pipe_c_handle( hdl_context, channel, 1 );

        // Register notify "ok to put" callback
        dpi_pipe_set_notify_callback(
            m_pipe_handle, notify_ok_to_put, &m_ok_to_put );
    }

    void put( const T &t ){
        svBitVecVal pipe_data[ SV_PACKED_DATA_NELEMS(NUM_WORDS*32) ];

        pack( t, pipe_data );

        while( !nb_can_put() )
            wait( m_ok_to_put );

        assert(
            dpi_pipe_c_try_send( m_pipe_handle,
                4, NUM_WORDS, pipe_data, 0 ) );
    }

    bool nb_put( const T &t ){
        if( !nb_can_put() )
            return false;

        svBitVecVal pipe_data[ SV_PACKED_DATA_NELEMS(NUM_WORDS*32) ];

        pack( t, pipe_data );

        assert(
            dpi_pipe_c_try_send( m_pipe_handle,
                4, NUM_WORDS, pipe_data, 0 ) );

        return true;
    }

    bool nb_can_put( tlm_tag<T> *t = 0 ) const {
        return dpi_pipe_c_can_send( m_pipe_handle, 4, NUM_WORDS ); }

    const sc_event &ok_to_put( tlm_tag<T> *t = 0 ) const {
        return m_ok_to_put; }
};

void pipeline_ingress_proxy<mytype,mytype::NUM_WORDS>::pack(
        const mytype &t, svBitVecVal pipe_data[] )
{
    pipe_data[0] = t.count;

    // Coerce double to long long integer.
    long long ll_data = (long long)t.data;

    pipe_data[1] = (svBitVecVal)ll_data;
    ll_data >>= 32;
    pipe_data[2] = (svBitVecVal)ll_data;

    pipe_data[3] = t.status;
}

#endif // _pipeline_ingress_proxy_hxx

//===========================================================================
// mytype.hxx
//
// @(#) $Id: mytype.hxx,v 1.3 2006/02/21 04:20:30 jstickle Exp $
//===========================================================================

//---------------------------------------------------------------------------
//   Mentor Graphics, Corp.
//
//   (C) Copyright, Mentor Graphics, Corp. 2003-2006
//   All Rights Reserved
//   Licensed Materials - Property of Mentor Graphics, Corp.
//
//   No part of this file may be reproduced, stored in a retrieval system,
//   or transmitted in any form or by any means --- electronic, mechanical,
//   photocopying, recording, or otherwise --- without prior written permission
//   of Mentor Graphics, Corp.
//
//   WARRANTY:
//   Use all material in this file at your own risk.  Mentor Graphics, Corp.
//   makes no claims about any material contained in this file.
//---------------------------------------------------------------------------
 
#ifndef _mytype_hxx
#define _mytype_hxx

using namespace sc_core;
using namespace std;
#include <iostream>

//______________                                              _______________
// class mytype \____________________________________________/ johnS 1-2-2004
//
// An arbitrary custom data type used to demonstrate passing of abstract data
// objects among SystemC SC_MODULEs over data channels.
//---------------------------------------------------------------------------

class mytype {
    public:
        enum { NUM_WORDS = 4 };
        int    count;
        double data;
        long   status;

        mytype( int a_count, double a_data, long a_status ){
            count = a_count;
            data = a_data;
            status = a_status;
        }

        //---------------------------------------------------------
        // Mandatory Methods:                        johnS 1-2-2004
        //   mytype()
        //   operator=()
        //   operator==()
        // 
        // Mandatory methods for custom types used with SystemC data
        // channels. C++ compile errors will result if these methods
        // are not defined for custom types used to parametrize SystemC
        // data channels such as sc_in<>, sc_out<>, sc_buffer<>,
        // sc_signal<>. This is only true when such types are passed by
        // value (which is safe but inefficient). When passed by
        // reference, the extra methods are not needed (and simulations
        // are more efficient).
        //---------------------------------------------------------

        mytype(){ } // Default constructor

        const mytype &operator=( const mytype &a_data ){
            count = a_data.count;
            data = a_data.data;
            status = a_data.status;
            return *this;
        }

        bool operator==( const mytype &a_data ) const{
            return count  == a_data.count  &&
                   data   == a_data.data   &&
                   status == a_data.status ? true : false;
        }
};

//---------------------------------------------------------
// Mandatory Functions:                      johnS 1-2-2004
//   sc_trace()
//   operator << ()
//
// Mandatory functions for custom types used with SystemC
// data channels. See explanation above for mandatory methods.
//---------------------------------------------------------

inline void
sc_trace(
    sc_trace_file* /*tf*/, const mytype& /*object*/,
    const string& /*name*/ ) { }

inline void
sc_trace(
    sc_trace_file* /*tf*/, const mytype* /*object*/,
    const string& /*name*/ ) { }


inline ostream &operator<<(ostream &out, const mytype &data){
    out << data.count << " " << data.data << " " << data.status << endl;
    return out;
}

#endif // _mytype_hxx
Received on Tue Feb 21 09:49:09 2006

This archive was generated by hypermail 2.1.8 : Tue Feb 21 2006 - 09:50:06 PST