breakthrough solution for "vendor induced" pipes deadlock ?

From: John Stickley <john_stickley_at_.....>
Date: Fri Jan 27 2006 - 07:30:39 PST
Greetings and ITC Techies,

I think I might have a breakthrough for our "deadlock"
on pipes. :-)

That thing that seems to be bothering Shabtay the most,
and perhaps with some justification, is that the pipes do
not have a thread neutral API that can be used to aid
implementations in adapting the user friendly pipe functions
implementation to arbitrary threading systems on the C side.

So, after thinking about it and looking at what we have
so far, it occurs to me that what we really need is *both*
of the following

1. A user-friendly, but thread-aware pipe interface
    (which we already have).

2. A lower level implementation-friendly, but thread-neutral
    pipe interface - essentailly implementation "hooks" to
    facilitate easy creation of adapters that allow implementation
    of the user-friendly API in selected C threaing environments
    (which Shabtay wants).

Shabtay, ye ask and ye shall receive !

Here's a solution I believe can be made to work that is,

1. Compatible with the existing easy-to-use API at the user level

2. Provides thread neutral "hooks" that implementations can
    choose to use to create adapter layers.

3. Easy to demonstrate a reference implementation of the blocking
    pipe calls that uses the hook functions. In fact, the examples
    I'm providing today show a working source code example of such
    an implementation for the HDL side.

So what I've done is kept the blocking user-friendly pipe
functions on the C side as is:

User-friendly C callins:
dpi_pipe_c_send()
dpi_pipe_c_receive()
dpi_pipe_c_flush()

A user would use only these functions.

But I've added 4 new "hook" functions that only a thread
specific implementation would use:

C hook functions:
dpi_pipe_c_try_send() - C callin
dpi_pipe_c_try_receive() - C callin

dpi_pipe_c_notify_ok_to_send() - C callback
dpi_pipe_c_notify_ok_to_receive() - C callback

The try_send() and try_receive() functions are essentially
non-blocking sends that return a status as to whether there
was room in the pipe (try_send()) or at least one transaction
in the pipe (try_receive).

The notify_ok_to_send() and notify_ok_to_receive() functions are
callbacks that can be called directly or indirectly from within
the thread-neutral implementation code to nofify the thread-aware
implementation code (but not user code !) on the C side
when it is OK to send or receive. By implementing the bodies of
these functions a vendor can put in thread specific code that takes
some action such as posting to an sc_event.

So the key here is that the 1st 2 hook functions have thread
neutral code. And the 2nd 2 hook functions are callbacks
called from within thread-neutral code that can be filled in
by some implementation wishing to create a thread-aware adapter
that implements the send() and receive() functions.

I've also defined the same functions on the HDL side for
full symetry:

User-friendly HDL callins:
dpi_pipe_hdl_receive()
dpi_pipe_hdl_send()
dpi_pipe_hdl_flush()

HDL hook functions:
dpi_pipe_hdl_try_send() - HDL callin
dpi_pipe_hdl_try_receive() - HDL callin

dpi_pipe_hdl_notify_ok_to_send() - HDL callback
dpi_pipe_hdl_notify_ok_to_receive() - HDL callback

I've attached the C and Verilog header files that provide
precise declarations of all of these functions.

In fact, in there you'll also find an actual source code
reference model showing how, on the HDL side, the hook functions
can be used in "adapters" that implement the user friendly functions.

A very similar scheme can easily be applied to any threading
system on the C side.

I've also uploaded the complete working example that actually
uses all the new hook functions (on both sides) and simulates
on any ModelSim 6.1/Linux installation.

You'll find it on anonymous FTP at ftp.ikos.com under,

    outgoing/scemi2_demo.tgz

The 32 bit binaries are built for Linux that runs on either
i386 or x86_64 platforms. It was tested on an RHEL 3.0
machine. Env.script and Makefile explain setup.

I hope this breaks the deadlock allows us to move forward
with pipes.

-- johnS

//===========================================================================
// dpi_pipes.h
//
// @(#) $Id: dpi_pipes.h,v 1.1 2006/01/27 07:08:05 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

#ifdef __cplusplus
extern "C" {
#endif

#include "svdpi.h"

//---------------------------------------------------------------------------
// dpi_pipe_c_send()                                         -- johnS 1-26-06
//
// These is the basic blocking send function for a transaction input pipe.
//
// dpi_pipe_c_receive()
//
// This is the basic blocking receive function for a transaction output pipe.
//---------------------------------------------------------------------------

void dpi_pipe_c_send(
    int pipe_id,             // input: intra-module pipe identifier
    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

void dpi_pipe_c_receive(
    int pipe_id,            // input: intra-module pipe identifier
    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_flush()                                        -- johnS 1-26-06
//
// Flush pipelined data.
//---------------------------------------------------------------------------

void dpi_pipe_c_flush(
    int pipe_id );       // input: intra-module pipe identifier

//---------------------------------------------------------------------------
// dpi_pipe_c_try_send()                                     -- johnS 1-26-06
//
// This is the basic non-blocking send function for a transaction input pipe.
// 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. 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(
    int pipe_id,             // input: intra-module pipe identifier
    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(
    int pipe_id,            // input: intra-module pipe identifier
    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_notify_ok_to_send()                            -- johnS 1-26-06
//
// This is the declaration for a callback function that is used to notify
// the C side that a transaction input pipe has space. This function
// is a thread neutral function that can be used by implementations
// of the block send function (dpi_pipe_c_send) in adaptations to
// selected C-based threading environments.
//
// dpi_pipe_c_notify_ok_to_receive()
//
// This is the declaration for a callback function that is used to notify
// the C side that a transaction output pipe has space. This function
// is a thread neutral function that can be used by implementations
// of the block send function (dpi_pipe_c_send) in adaptations to
// selected C-based threading environments.
//

void dpi_pipe_c_notify_ok_to_send(
    int pipe_id );       // input: intra-module pipe identifier

void dpi_pipe_c_notify_ok_to_receive(
    int pipe_id );       // input: intra-module pipe identifier

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

#endif // _dpi_pipes_h

// @(#) $Id: dpi_pipes.vh,v 1.1 2006/01/27 07:08:10 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.
//---------------------------------------------------------------------------

//===========================================================================
// dpi_pipe_hdl_receive()                                       johnS 9-15-05
// dpi_pipe_hdl_send()
//
// Receive, send pipelined data
//===========================================================================

`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_nb_get()                                       johnS 9-15-05
// dpi_pipe_hdl_nb_put()
//
// 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

    if( !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] );
        if( !dpi_pipe_hdl_try_receive( pipe_id,
                bytes_per_element, num_elements, num_elements_read,
                data, eom ) )
            $display( "ERROR: Unexpected return from dpi_pipe_hdl_try_receive()" );
    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

    if( !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] );
        if( !dpi_pipe_hdl_try_send( pipe_id,
                bytes_per_element, num_elements, data, eom ) )
            $display( "ERROR: Unexpected return from dpi_pipe_hdl_try_send()" );
    end
endtask

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

import "DPI-C" context task dpi_pipe_hdl_flush(
        input int pipe_id );    // input: intra-module pipe identifier
Received on Fri Jan 27 07:30:58 2006

This archive was generated by hypermail 2.1.8 : Fri Jan 27 2006 - 07:31:41 PST