sylefeb / Silice

Silice is an easy-to-learn, powerful hardware description language, that simplifies designing hardware algorithms with parallelism and pipelines.
Other
1.28k stars 77 forks source link

Asymmetry in controlling how inputs/outputs are registered #125

Open sylefeb opened 3 years ago

sylefeb commented 3 years ago

Issue

There is currently an asymmetry in the fact that the behavior of outputs are controlled in the algorithm definition (output or output!), while the behavior of the inputs is controlled at instantiation time (<: or <::). This reflects the fact that input flip-flops are indeed in the parent, while output flip-flops are indeed in the instance. However, this is not as convenient as if this could be controlled at instantiation time.

Possible approach

Now that algorithms are truly instanced by Silice, we could implement the following: input would remain as is and outputs would all become output! (see note below on backward compatibility). Adding registers would become solely controlled from binding using <:, <:: for inputs, and :>, ::> (new) for outputs. This would only change, for the outputs, whether the wire connects to the D or Q side ; as is is the case currently using output/output!. But this choice would now be made from the parent.

Open question: When binding groups what is then the meaning of <::>? registers on both input and outputs? We might want to control these separately ... introduce a separator? e.g. <:|:>, <::|:>, etc.?

Open question: Behavior in calls of the form () <- ... <- (), and in 'dot' syntax access of ins/outs?

Ensuring backward compatibility

There would be little choice but to change the keywords input/output for (e.g.) in/out so that we can preserve the previous behavior, not break any code, and provide a deprecation warning. This is also a shorter syntax, fits better with inout, so might not be a big issue.

rob-ng15 commented 3 years ago

Sounds promising, I think.

I am happy to try this on PAWS, but I'd need to know exactly what to change.

Rob.

On Sat, 17 Apr 2021 at 08:20, sylefeb @.***> wrote:

Issue

There is currently an asymmetry in the fact that the behavior of outputs are controlled in the algorithm definition (output or output!), while the behavior of the inputs is controlled at instantiation time (<: or <::). This reflects the fact that input flip-flops are indeed in the parent, while output flip-flops are indeed in the instance. However, this is not as convenient as if this could be controlled at instantiation time. Possible approach

Now that algorithms are truly instanced by Silice, we could implement the following: input would remain as is and outputs would all become output! (see note below on backward compatibility). Adding registers would become solely controlled from biding using <:, <:: for inputs, and :>, ::> (new) for outputs. This would only change, for the outputs, whether the wire connects to the D or Q side ; as is is the case currently using output/ output!. But this choice would now be made from the parent.

Open question: When binding groups what is then the meaning of <::>? registers on both input and outputs? We might want to control these separately ... introduce a separator? e.g. <:|:>, <::|:>, etc.?

Open question: Behavior in calls of the form () <- ... <- (), and in 'dot' syntax access of ins/outs? Ensuring backward compatibility

There would be little choice but to change the keywords input/output for (e.g.) in/out so that we can preserve the previous behavior, not break any code, and provide a deprecation warning. This is also a shorter syntax, fits better with inout, so might not be a big issue.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/sylefeb/Silice/issues/125, or unsubscribe https://github.com/notifications/unsubscribe-auth/AN4SYT5V4P7CUKKYQWLQ6RLTJEZE7ANCNFSM43CZDKHQ .

sylefeb commented 3 years ago

Thanks! This will be the focus of the next changes I think, and should resolve a couple other open issues in passing (e.g. #49, #126). I'll make sure not to break any existing code.

sylefeb commented 3 years ago

One difficulty with this idea, is how it interacts with interfaces. Right now, an interface can specify how the user should deal with its output wrt. the inputs. For instance here is the user interface for a BRAM:

interface bram_port {
  output! addr,
  output! wenable,
  input   rdata,
  output! wdata,
}

Here it ensures the users output are immediate (not registered) so that the input from BRAM is available next cycle. The user is free to register the input internally, but the interface defines a clear contract on how the BRAM should be used and this gets applied upon binding using <:> (the interface can also freely mix output! and output).

This capability of letting the interface specify the type of binding seems important to preserve...