chisel icon indicating copy to clipboard operation
chisel copied to clipboard

Unifying Chisel._ and chisel3._ connection semantics

Open mwachs5 opened this issue 3 years ago • 1 comments

Type of issue: Feature Request

Is your feature request related to a problem? Please describe.

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
})))

Describe the solution you'd like

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())) }

Describe alternatives you've considered

keeping things the same as they are.

Additional context

What is the use case for implementing this feature?

Being able to unify and improve LegacyChisel vs chisel3 connection semantics to overall simplify the code base.

mwachs5 avatar Jul 25 '22 12:07 mwachs5

@azidar I grabbed the great writeup from #2634 to an issue since it seems like we might have various PRs that fall into this issue heading

mwachs5 avatar Jul 25 '22 12:07 mwachs5

i was thinking about this recently, does it make sense to have stripFlipsOf be actually an opaque type? so that the scala type is actually StrippedFlipsOf[BidirType]?

to me this maybe makes it more sense for things like:

a: A :#= b: A

maybe makes more sense explicitly as:

a: StrippedFlipsOf[A] :#= b: A

mwachs5 avatar Mar 08 '23 23:03 mwachs5

I'm not sure we can do it that way do to the prevalence of val x: DecoupledIO[UInt] = Output(new DecoupledIO(UInt(1.W))), which strips the flips, but the return scala type is still DecoupledIO[UInt]. I think your proposal would change the scala type of all return values from Input and Output.

azidar avatar Mar 09 '23 19:03 azidar

scala type of all return values from Input and Output

Right, I guess that's what I'm explicitly saying. Do we want them to have the same type, and if so, why? Given that we could define :#= on the types that we explicitly mean. What is the other reason for them having the same type?

mwachs5 avatar Mar 09 '23 19:03 mwachs5

Gotcha. Yeah so maybe in the long term its a better way to have stripflipsof

azidar avatar Mar 09 '23 21:03 azidar