Skip to content
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

(Optionally) Sequential Black Boxes #2231

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

alex-mckenna
Copy link
Contributor

This PR adds the ability to define black boxes which can render in concurrent and sequential contexts. A new template tag ~ISSEQUENTIAL is provided, which templates can use to provide alternative implementations for the two contexts.

NOTE: This branch is based off #2230, not master, so that should be merged first

Still TODO:

  • Write a changelog entry (see changelog/README.md)
  • Check copyright notices are up to date in edited files
  • Write tests showing concurrent and sequential output with the same result in simulation (for some primitives like Vector.map etc. which can be defined in both contexts)

@alex-mckenna alex-mckenna force-pushed the netlist-seq-blackboxes branch 2 times, most recently from 0843269 to ae8dcbd Compare June 21, 2022 08:47
Alex McKenna added 10 commits June 22, 2022 14:27
In NetDecl', the type of the decl was either a HWType or raw text.
Since only the HWType branch was ever used in Clash, this should
be simplified.
The function `id2identifier` is an unsafe version of `fromCoreId`
in the netlist identifier module. It makes more sense for it to
be defined there, so callers can see it is obviously unsafe.
When producing sequential and concurrent code, there are restrictions
for how the same declared signal can be assigned which depend on the
HDL being targeted. In short, these are

    VHDL: A `signal` can be assigned continuously, or procedurally
    with non-blocking assignment. A `variable` can only be assigned
    procedurally with blocking assignment.

    Verilog: A `wire` can only be assigned continuously. A `reg`
    can only be assigned procedurally, but can be assigned both
    non-blocking and blocking.

When the backend produces HDL, it needs to know the type of a
declaration to render it. With the `WireOrReg` type, this was easy
for VHDL, but does not help differentiate between if a signal is
intended to be a VHDL signal or variable. A more general type is
now provided which provides the extra information to make this
choice:

```haskell
data Blocking = Blocking | NonBlocking
data Usage    = Cont | Proc Blocking
```

Since a declaration can accept more than one type of assignment,
the usage is not tracked with the declaration like `WireOrReg` was,
but tracked in the assignments and a usage map is created for every
component (tracking declared signals to their most restrictive use).
When producing netlist, the current use of a signal should be
checked to ensure that generated code only produces assignments
that are valid for the backend being targeted.
The environment of the netlist monad now contains the "style" of
HDL to generate, i.e. concurrent or sequential. This is just a
refactoring to make the information accessible without needing to
thread it through every netlist function.
Depending on the current style of HDL being produced, we want to
be able to change the template of black boxes. However, this may
change the type of assignment to the result signal in the template.

Consider a template for an `fmap` implementation. In a concurrent
context we may choose to produce a generate statement, which uses
continuous assignment to the result variable. In a sequential
context we would instead use a for loop with procedural assignment.
There is now a tag to test if the black box is being rendered in
a context which is concurrent or sequential. This allows the
template to provide a different implementation when a black box
can be implemented in both styles.

Somewhat annoyingly, templates can currently be rendered in the
wrong context with no warning until the HDL is given to a vendor
tool. It may be the case that many templates need to be wrapped
with something like

```
~IF ~ISSEQUENTIAL ~THEN ~ERR["no implementation possible"] ~ELSE ... ~FI
```

or vice-versa for templates that do not allow use in concurrent
contexts.
@alex-mckenna
Copy link
Contributor Author

Me and Leon had a discussion about this a while ago, so I think it makes sense to add what I remember from that here.

  • The templates which can be concurrent and sequential are going to get ridiculous, especially given things like ~GENSYM[i] needing a unique i for every occurrence in a template (not just all the occurrences hit when the template is instantiated. It would probably be a better idea to allow concurrent and sequential versions of templates to be given separately.

  • For black boxes which only support either concurrent or sequential (but not both), Clash should be able to handle this in some useful way. This may be throwing an error in netlist generation when something is used incorrectly, or potentially floating these instantiations to somewhere they can appear (this would depend on the work in netlist-scopes being finished).

  • While the original plan I had for "getting sequential Clash as quickly as possible" was to extend SimIO to work with all HDL, it should be no more difficult in practice to make all netlist sequential by default. With netlist-scopes this becomes a case of starting with an empty sequential scope inside an empty concurrent scope so inherently concurrent things are still floated up correctly (instead of just an empty concurrent scope).

I think these were the main points. Anything I forgot @leonschoorl?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant