[libre-riscv-dev] pipeline sync issues

Luke Kenneth Casson Leighton lkcl at lkcl.net
Wed Apr 10 06:59:20 BST 2019

On Wed, Apr 10, 2019 at 5:45 AM Jacob Lifshay <programmerjake at gmail.com> wrote:

> I think the problem derives from using code that has slightly different
> semantics around ready/valid. The semantics I used for the code I wrote are
> (copied from the proposal I'm writing):
>         ready_to_prev is a signal that is set by this stage to indicate that
>         data can be transferred from the previous stage to this stage at the
>         next clock edge if valid_from_prev is asserted.
>         valid_from_prev is a signal that is set by the previous stage to
>         indicate that data can be transferred from the previous stage to
> this
>         stage at the next clock edge if ready_to_prev is asserted.
>         valid_from_prev should not be combinationally dependent on
>         ready_to_prev to avoid logical loops.

 that sounds like the industry-standard write-enable semantics :
p_o_ready & p_i_valid both need to be asserted for input to be

 it also doesn't explain why UnbufferedPipeline (et al) *ignore*
p_o_ready entirely.  it's really important information as it
determines (or more like "declares") when the data is to *be* valid.

 the point being: the truth table for UnbufferedPipeline has a case
where p_o_ready was *not* set, p_i_valid *is* set, and consequently
*invalid* data is sent on through the system.

> Note how all the data transfers logically occur at a clock edge, not
> in-between clock edges.


> I think the semantics you were using are that ready
> and valid defines if a data transfer can occur in the next period
> in-between clock edges,

 no, it's not.  that's not physically possible. there's no logic at
all that could possibly involve "in-between" clock edges.

 look again closely at the truth tables, side-by-side.
UnbufferedPipeline *ignores* the case where p_o_ready is LOW and
p_i_valid is HIGH.

 that's i believe the source of the problem.

so i agree that the semantics (the way the paragraphs have been
stated) are correct, as they sound precisely like the
industry-standard write-enable semantics deployed by wishbone and

... it's just that the implementation is wrong and doesn't conform with it.

> which is different from the semantics I was using
> in that, in the code you wrote, ready has to be asserted earlier than in
> the code I wrote.

 that's down to the fact that the previous stage has to be told in the
*previous* cycle that it is free and clear to send the data.

 the contract from the sender's perspective:

 * data and n_o_valid are sent *together* (to arrive on a future
cycle) and are only sent when n_i_ready is valid (in THIS cycle)

the contract from the recipient's perspective: bear in mind that

(1) n_i_ready of the sender was set by p_o_ready from the *recipient* and
(2) what was the "future" cycle as far as the recipient is concerned
is now the PRESENT cycle of the sender, and
(3) what was the "present" cycle of the sender is the PAST cycle of
the recipient

 * because p_o_ready has to be set in what was the PAST, its present
state MUST be utilised to determine if the incoming data is valid, IN
COMBINATION with the fact that data-PLUS-valid are both synchronously

this is why we see (p_o_ready & p_i_valid) being used to determine if
the incoming data is to be placed into a register.

and if those two are not tested together, it *will* result in invalid
data being accepted.

note: if we don't conform to the industry-standard practices for
ready/valid, we will not be able to use SyncFIFO in our designs.


More information about the libre-riscv-dev mailing list