Description
It seems that handshake's LazyFork
violates a required property for composable dataflow circuits:
Consider the following example:
handshake.func @test(%arg0: none) -> (none) {
%0:2 = lazy_fork [2] %arg0 : none
%outCtrl = join %0#0, %0#1 : none, none
return %outCtrl: none
}
when lowering this to FIRRTL and feeding it into firtool
it will complain that there is a cycle involving the valid and ready signals of %0
. LazyFork
will only set the output's valid signal once all of them are ready to receive something. Join
on the other hand, waits until all inputs are valid, before it sets their ready signals.
The paper which introduces compositional dataflow circuits states the following:
We avoid combinational cycles by insisting each cycle in the dataflow network have at least one
data and one control buffer (see Section 4) and by insisting no block has a combinational path from
a ready to a valid signal.
While we ensure the first property with buffer insertions, the latter is violated by LazyFork
.
It seems that a correct LazyFork
implementation requires changes to ensure it can be used correctly. Not sure if it will then still be "cheaper" than a normal/eager fork, though.