chipsalliance / chisel

Chisel: A Modern Hardware Design Language
https://www.chisel-lang.org/
Apache License 2.0
3.93k stars 589 forks source link

Clarifying Directionality in Chisel Types #2643

Open mwachs5 opened 2 years ago

mwachs5 commented 2 years ago

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:

Expressing Chisel._ semantics:

Expressing chisel3._ semantics:

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 commented 2 years ago

@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 commented 1 year ago

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

azidar commented 1 year ago

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.

mwachs5 commented 1 year ago

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?

azidar commented 1 year ago

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