Per >

ServiceLoop() has been stirring again.  Specifically, a question

has arisen about the pseudo code for ServiceLoop() in the 1.1 spec.

This code (on p. 47) consists of two independent loops.  The

first loop handles all pending input messages.  The second loop

handles what we've called service requests.  The way I read this

code the second loop cannot start until all pending input messages

have been sent to the HDL side.

 

Now, here is a scenario to consider: To make things simple suppose

there is a single input port on the HDL side and one or more

output ports (the exact number does not matter).  Now suppose two

input messages have been sent using Send() before ServiceLoop()

was entered.  Further assume that for whatever reason, the BFM

on the HDL side is keeping ReceiveReady on the input port deasserted.

Assume TransmitReady is also deasserted at the time ServiceLoop() is

entered (any previous message has already been transferred).

 

When ServiceLoop() is entered, the first while loop will send the

first input message to the port.  TransmitReady will then be asserted.

Now, what happens with the second message?  If the transactor does

not assert ReceiveReady the message cannot be sent to the port since

the first message is still waiting to be transferred.  Hence, the

first while loop will loop forever or at least until the transactor

decides to assert ReceiveReady, that is we have a deadlock.  Is this

a correct interpretation of the pseudo code?  What about the semantics

that was originally for the ServiceLoop() function?

 

The purpose of the above questions is merely to ensure I understand

the behavior of ServiceLoop() correctly.  I am not suggesting there

may be a problem here.  As we have discussed in the past, there are

many ways that the user can deadlock the system.  This appears to

be one of them.  One possible way to avoid such a deadlock is to

provide feedback to the SW side from the HW side via an output

port or using the input ready propagation mechanism to prevent the

SW side from sending messages when the BFM is not ready/willing to

receive them.

 

I forgot to mention that I am assuming that the HW side infrastructure

only has room for one input message per input port.  If it has room

for n messages we can extend the argument to n+1 messages.  The

deadlock is still possible if I'm interpreting the pseudo code

correctly.  To my knowledge SCE-MI does not impose any requirements

on the number of messages the HW infrastructure is supposed to buffer

so assuming a buffer depth of 1 message is perfectly reasonable,

right?

< Per

 

JohnS >

This is indeed a way of deadlocking the System.

 

To be "well behaved" and avoid this transactors need to be

designed in one of two ways:

 

1. They are prepared to always take input (on any uclock)

    to avoid a backup on the channel.

 

    In this scenario it is often the case that an output

    port is ultimately used to tell the S/W side when it

    is OK to send the next input, thereby acheiving throttling

    that way.

 

    A caution is that, in certain scenarios this can cost extra

    output ports (where none might otherwise be needed) which can

    be expensive and using an input ready mechanism (#2 below) might

    be cheaper.

 

2. If 1 is not possible, they need to deploy input ready callbacks

    as flow control whereby the S/W model is well enough behaved

    to know not to messages until the input ready callback is

    received.

 

For #2 good streaming performance can be realized if

the input port transactor asserts ReceiveReady immediately

for the next data even as it takes the current data and processes

it further rather than waiting until it processes the

first data and then decides "ok, now I'm ready for the

next data, let me assert receiveReady".

 

Of course with SCE-MI 2 pipes the beauty is that the

infrastructure, not the user can worry about all of this.

 

<JohnS