Generate dynamic bundle

Viewed 105

In my project, I have many different custom Bundle. They can be completely different. For example these ones:

class MyBundle extends Bundle {
  val v1 = UInt(8.W)
  val v2 = Bool()
  val v3 = UInt(4.W)
}

class MyBundle2 extends Bundle {
  val v4 = UInt(18.W)
  val v5 = UInt(2.W)
}

...

Instead of manually creating new Bundle to perform each operation, I want to be able to generate for all of them the corresponding Bundle. So for MyBundle, I want to do:

// Must be generated for each Bundle
class MyGenBundle extends Bundle {
  val v1 = UInt(log2Ceil(8 + 1).W) // width = MyBundle.v1 width + 1
  val v2 = UInt(log2Ceil(1 + 1).W) // width = MyBundle.v2 width + 1
  val v3 = UInt(log2Ceil(4 + 1).W) // width = MyBundle.v3 width + 1
}

class MyModule extends Module {
  ...
  ...
  val w_b = Wire(new MyBundle())
  val w_gb = Wire(new MyGenBundle())

  // Must be automated for each Bundle
  w_gb.v1 := PopCount(w_b.v1)
  w_gb.v2 := PopCount(w_b.v2)
  w_gb.v3 := PopCount(w_b.v3)
}

My goal is to automatically generate MyGenBundle (or similar directly in MyModule) from MyBundle, and perform in MyModule the same operation to all signals. It also means that I need to dynamically address all signals in each Bundle. Finally, I think the solution can have the following form:

val w_b = Wire(new MyBundle())
val w_gb = Wire(new AutoGenBundle(new MyBundle())) // AutoGenBundle generates a Bundle from parameter

val v_sig = Seq(v1, v1, v3)                        // Can be recovered automatically 
                                                   // from w_b.elements I think
foreach (s <- v_sig) {
  w_gb."s" := PopCount(w_b."s")                    // Here "s" the dynamic name of the signal
}                                                  // But how in the real case ?

Is this working technically possible in Chisel/Scala? If so, do you have any ideas for implementing it?

1 Answers

Basic solution is to use the MixedVec chisel type for GenericBundle

class MyBundle extends Bundle {
  val v1 = UInt(8.W)
  val v2 = Bool()
  val v3 = UInt(4.W)
}

class GenericBundle[T <: Bundle](data: T) extends Bundle {
  val v = MixedVec(data.elements.values.map(x => UInt(log2Ceil(x.getWidth + 1).W)).toList)

  def popCount(data: T): Unit = {
    data.elements.values.zip(v).foreach { case (left, right) =>
      right := PopCount(left.asUInt())
    }
  }
}

class MyModule extends MultiIOModule {
  val w_b = IO(Input(new MyBundle))
  val w_gb = IO(Output(new GenericBundle(w_b)))

  w_gb.popCount(w_b)
}

Related