Skip to content

Conversation

azidar
Copy link
Contributor

@azidar azidar commented Jul 21, 2022

Background: Chisel._ vs chisel3._ directionality

In Chisel._, IO has an implicit output direction, and Flipped is used for two things:

  1. Define relative direction of a field with respect to its parent bundle
  2. To change the implicit output to an implicit input of IO
val io = IO(new Bundle { // implicit output
  val x = Flipped(UInt()) // x is flipped relative to bundle, so it is an input
  val y = UInt() // y is aligned relative to bundle, so it is an output
})

You can declare an input port using the (2) kind of Flipped:

val io = IO(Flipped(new Bundle { // implicit input
  val x = Flipped(UInt()) // x is flipped relative to bundle, so it is an output
  val y = UInt() // y is aligned relative to bundle, so it is an input
}))

In chisel3, IO does not have an implicit direction, but Input and Output are specified on types, which coerce all subfields of the type to the same direction. Flipped inverts the absolute direction so Input -> Output and Output -> Input.

val io = IO(new Bundle { // no implicit direction
  val x = Input(UInt()) // x is an input
  val y = Output(UInt()) // y is an output
}))

You can switch directions with Flipped:

val io = IO(Flipped(new Bundle { // Swap all absolute directions
  val x = Input(UInt()) // x is flipped so it is an output
  val y = Output(UInt()) // y is flipped so it is an input
})))

Unifying directionality with new primitives

Both mechanisms of describing field directions can be unified with the following (conceptual) primitives:

  • Flipped: a field's relative direction is reversed with respect to its parent bundle
  • Aligned: a field's relative direction is the same with respect to its parent bundle (is implicit)
  • Outgoing: an IO whose implicit direction is output
  • Incoming: an IO whose implicit direction is input
  • stripFlipsOf: a type-generator that aligns all subfields, recursively
  • reverseFlipsOf: a type-generator that flips all subfields, recursively

Expressing Chisel._ semantics:

  • IO(new Bundle)) becomes Outgoing(new Bundle)
  • IO(Flipped(new Bundle)) becomes Incoming(new Bundle); note that Outgoing(reverseFlipsOf(new Bundle)) is the same, but I think it makes sense to have Incoming as well.
  • new Bundle { val x = UInt() } is new Bundle { val x = Aligned(UInt()) }, or unchanged as Aligned is implicit
  • new Bundle { val x = Flipped(UInt()) } is unchanged

Expressing chisel3._ semantics:

  • IO(new Bundle)) becomes Outgoing(new Bundle)
  • IO(Flipped(new Bundle)) becomes Incoming(new Bundle)
  • new Bundle { val x = Output(UInt()) } is new Bundle { val x = Aligned(stripFlipsOf(UInt())) }
  • new Bundle { val x = Input(UInt()) } is new Bundle { val x = Flipped(stripFlipsOf(UInt())) }

How this PR unifies these things

Just like we can express Chisel/chisel3 with new primitives, we can represent the new primitives with Chisel/chisel3 APIs. The only thing that was missing was (1) ALWAYS apply the implicit output from IO (or implicit input if a flip is there), and (2) enable mixing Input/Output with Flipped. This means that effectively, Input becomes Flipped(stripsFlipsOf(..)) and Output becomes Aligned(stripsFlipsOf(..)), and now the semantics can coexist. Basically, this change defines how Chisel._'s relative directions resolve in chisel3. This should not break any code, because previously it was an error.

Future work will be to add the new primitives as they are, and refactor Input/Output etc to just call the new primitives. In the meantime, we can change the semantics so that this change is easier, and we can get rid of compatibility mode.

Contributor Checklist

  • Did you add Scaladoc to every public function/method?
  • Did you add at least one test demonstrating the PR?
  • Did you delete any extraneous printlns/debugging code?
  • Did you specify the type of improvement?
  • [N/A] Did you add appropriate documentation in docs/src? Will do this later when we add more primitives
  • Did you state the API impact?
  • Did you specify the code generation impact?
  • Did you request a desired merge strategy?
  • Did you add text to be included in the Release Notes for this change?

Type of Improvement

  • new feature/API

API Impact

Adds an API, where you can now declare bundles that have both Flipped and Input/Output.

Backend Code Generation Impact

None

Desired Merge Strategy

  • Squash: The PR will be squashed and merged (choose this if you have no preference.

Release Notes

Remove restriction that Bundles have to only declare fields with absolute directions (Input/Output) or relative directions (Flipped).

Reviewer Checklist (only modified by reviewer)

  • Did you add the appropriate labels?
  • Did you mark the proper milestone (Bug fix: 3.4.x, [small] API extension: 3.5.x, API modification or big change: 3.6.0)?
  • Did you review?
  • Did you check whether all relevant Contributor checkboxes have been checked?
  • Did you do one of the following when ready to merge:
    • Squash: You/ the contributor Enable auto-merge (squash), clean up the commit message, and label with Please Merge.
    • Merge: Ensure that contributor has cleaned up their commit history, then merge with Create a merge commit.

@azidar azidar requested a review from jackkoenig July 21, 2022 18:20
Copy link
Contributor

@jackkoenig jackkoenig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good but I would like to see more examples showing what is now possible.

Also should there be something in docs/ for this?

@azidar
Copy link
Contributor Author

azidar commented Jul 22, 2022

So I could write docs, but I kind of want to wait until we actually add the new operators/primitives, then its easier to describe it. As is, all the docs are still technically correct, and this interoperability doesn't need to be advertised yet.

Copy link
Contributor

@jackkoenig jackkoenig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM, 1 suggested improvement to a comment and 1 nit

Co-authored-by: Jack Koenig <koenig@sifive.com>
@azidar azidar enabled auto-merge (squash) July 22, 2022 22:40
@mwachs5
Copy link
Contributor

mwachs5 commented Jul 23, 2022

Can you fill out the release notes? What is THIS PR actually doing?

@azidar
Copy link
Contributor Author

azidar commented Jul 25, 2022

Can you fill out the release notes? What is THIS PR actually doing?

I thought I did?

Remove restriction that Bundles have to only declare fields with absolute directions (Input/Output) or relative directions (Flipped).

@ekiwi
Copy link
Contributor

ekiwi commented Jul 25, 2022

@azidar Since there seem to be many ways of doing things, would you mind documenting, what the recommended style is? Maybe at least update the examples in our readme which should probably be updated anyways to take advantage of the MultiIO by default feature and not declare useless anonymous Bundles.

Would the Blinky example now be?:

class Blinky(freq: Int, startOn: Boolean = false) extends Module {
  val led0 = Outgoing(Bool())
  // Blink LED every second using Chisel built-in util.Counter
  val led = RegInit(startOn.B)
  val (_, counterWrap) = Counter(true.B, freq / 2)
  when(counterWrap) {
    led := ~led
  }
  led0 := led
}

@azidar
Copy link
Contributor Author

azidar commented Jul 25, 2022

Since there seem to be many ways of doing things, would you mind documenting, what the recommended style is?

I believe your Blinky example is correct, but we haven't actually added Incoming or Outgoing (or even decided that's the right names for them). That is future work that I'd like to do. That's why right now I don't want to document anything unnecessarily because I don't think the work is ready to be user facing.

Perhaps what would help is if I wrote up an actual proposal that we can discuss?

@mwachs5
Copy link
Contributor

mwachs5 commented Jul 25, 2022

Yep release notes look good now

@mwachs5
Copy link
Contributor

mwachs5 commented Jul 25, 2022

Perhaps what would help is if I wrote up an actual proposal that we can discuss?

That's why I copied all the good write up above into its own issue :) #2643

@azidar azidar merged commit 1aea4ef into master Jul 27, 2022
@azidar azidar deleted the unify-legacychisel-chisel3-directionality branch July 27, 2022 17:35
@mwachs5
Copy link
Contributor

mwachs5 commented Sep 30, 2022

Did we consider backporting this to 3.5? I know it's strictly a change in behavior, but its a more-things-work-instead-of-being errors which might help in upgrading.

@mwachs5
Copy link
Contributor

mwachs5 commented Nov 8, 2022

assigning this to 3.5.x milestone to attempt opening a backport there

mergify bot pushed a commit that referenced this pull request Nov 8, 2022
Co-authored-by: Jack Koenig <koenig@sifive.com>
(cherry picked from commit 1aea4ef)

# Conflicts:
#	core/src/main/scala/chisel3/Aggregate.scala
#	core/src/main/scala/chisel3/Module.scala
#	src/test/scala/chiselTests/Direction.scala
@mergify mergify bot added the Backported This PR has been backported label Nov 8, 2022
mergify bot added a commit that referenced this pull request Nov 10, 2022
* Unify Chisel2 and chisel3 directionality (#2634)

Co-authored-by: Jack Koenig <koenig@sifive.com>
(cherry picked from commit 1aea4ef)

# Conflicts:
#	core/src/main/scala/chisel3/Aggregate.scala
#	core/src/main/scala/chisel3/Module.scala
#	src/test/scala/chiselTests/Direction.scala

* fix up backport

* fix up backport

* clean up diff

* make test order like it was on master

Co-authored-by: Adam Izraelevitz <adam.izraelevitz@sifive.com>
Co-authored-by: Megan Wachs <megan@sifive.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backported This PR has been backported
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants