-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Determining the static interface for calyx
components
#1725
Comments
Thanks for writing this up, one small question on 2. (Edit: actually I think we should probably just abandon 2 as an idea, so my question isn't really relevant):
Is it necessary for the component to be ready to accept inputs every cycle? In other words, can't we just make it the Calyx programmer's responsibility to use the component correctly if the component's II is not 1? The only reason why I say this is that it seems like we wouldn't be able to represent a component that has an II of 2 or more in this case. Lmk if there's something I'm missing. Another question: |
I think (2) is not tenable because if your module has II > 1, then you cannot correctly use it because you have no way to know when it started its first execution. |
Just to summarize our synchronous discussion from today: What we want: a one cycle go assertion
Asymmetry with groupsA The main difficulty is probably going to be compiling
We currently compile it like this:
However, for the "one cycle go assertion" interface, we would have to compile it like this:
There may also be other issues that I have forgotten, so please add them in responses here. |
Excellent summary. I think that's exactly where we stand. I guess the strawman plan here could be to just live with the asymmetry between components and groups... do folks know of bad problems with that? Maybe inlining? |
DecisionJust going to update this with our synchronous discussion: we decided that the asymmetry between groups and components is (probably) acceptable, since there is an asymmetry in between how components and groups are used: components can be pipelined in their execution, while groups cannot. Therefore, we can (at least for now) try to implement the interface and we'll live with the asymmetry. QuestionOne question that I just thought of: currently, we infer the latency of registers and multipliers by looking at the
|
Thanks for following up on this @calebmkim! Thoughts on "definitely static" primitives like registers:
My point in mentioning (1) & (2) is that, notionally, we should think of Does this philosophy resonate? |
@andrewb1999 agrees that the new "assert |
Right, this seems like the way to me! To put it another way, we want to have two nonoverlapping categories of components:
Then we might want to create a small third category for special cases:
One could argue that we should eliminate category 3, and create two different primitives called |
Right! The argument for keeping category 3 is that name punning for very common things like registers is useful and we expect synthesis tools to remove the unconnected |
One more note: for |
Hm, not sure I follow. If you promote something, it goes from 3 to 1 right? This is because we're saying that we definitely don't need to use the |
I think we have to rethink what the latency of a static component actually means, especially for pipelined components. Writing a pipelined component would probably have a control program that looks something like this:
But in this case, the latency of the control program would be the II, not the latency of the component. Using a
won't work, since we only have one fsm, which can only be at one value: intuitively, this means we cannot be executing multiple stages of the pipeline at the same time: we are only executing the stage that the ProposalIt might be good to keep the current decision, except for Doing this would also create somewhat of an analogy with static Calyx control programs: for example, the static systolic array has a while loop: the while loop's body has latency of 1, since that's the "II" of the loop, not the number of cycles to perform a multiply & accumulate. This won't necessarily change the way we are going to compile static components, it will only affect how people should think about the latency of static components. |
@paili0628 My understanding of the annotation is exactly the same! That is, for sequential components, the annotation represents both the II and the latency but for pipelined component, it tells you when you can re-invoke the module. @calebmkim thoughts? |
Yeah I agree with the above^. I think this all sounds good. |
I think this II/latency decision sounds fine too! Namely, it fulfills these desiderata that seem important to me:
|
Following up on this earlier thread between @calebmkim and @rachitnigam:
What I believe @calebmkim is saying is:
So we could actually just not do the second step, and only ever automatically move components into category 3 (never 2), which would make them behave like Is this a good trade-off? Not entirely sure yet, but I wanted to confirm this is what @calebmkim is envisioning. |
Yeah, that's exactly what I was thinking. |
Should we add a new |
It's a pretty good idea. This would end up being, like, a super restrictive embedding of a subset of Filament types… as in, a Filament component with a simple signature something like this:
Could compile to a Calyx signature like this:
|
Subsumed by #1754 |
We should make a decision on exactly what the interface for the
static component
would look like. In particular, there are 3 options:go
signal that triggers for exactly 1 cycle. The component will be 'ready' to accept inputs again after n cycles (i.e., the static latency refers to the II). (No done signal)go
nor adone
interface. The output ports hold the outputs relevant to the value on the input ports exactly n cycles ago. In this case the component will have to be 'ready' to accept inputs every cycle, since there's no way to distinguish between valid and invalid signals.go
signal that has to be continuously triggered until adone
signal is up (the static latency refers to how many cycles have to elapse since the first cycle thego
signal is triggered until thedone
signal is up).Correspondingly, there are also two options to define the dynamic interface:
go-done
interface with no pipelining.go-ready-done
interface, where thego
still has the same semantic meaning, thedone
means that a valid output is produced on the output ports, and theready
means that the component is now 'ready' to accept inputs (i.e., the component only 'accepts' inputs whengo==1'd1 & ready==1'd1
.The text was updated successfully, but these errors were encountered: