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