FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages

ChiselのパラメタライズによりGenericなモジュールを作成する手法

https://cdn-ak.f.st-hatena.com/images/fotolife/m/msyksphinz/20181105/20181105012126.png

Chiselによりインタフェースのパラメタライズの検討を行う。例えば、汎用インタフェースを使用してバスのマルチプレクサを構成することを考える。

インタフェースとしては以下のものを使う。以下のGenBundleTで汎用化されている。valid, sideband, dataの信号線が用意されており、dataは一般化されており、任意のデータ型を渡すことが可能である。

class GenBundle[T <: Data](dataType: T) extends Bundle {
  override def cloneType: this.type =
    new GenBundle(dataType).asInstanceOf[this.type]

  val valid = Output(Bool())
  val sideband = Output(UInt(10.W))
  val data  = Output(dataType)
}

例えば、以下のような汎用化を考える。nポートのインタフェースから、1つのポートを選んで返す。

class GenericArbiter[T <: Data](val gen:T, val n: Int) extends Module {
  val io = IO(new Bundle {
    val in = Input(Vec(n, gen))
    val out = Output(gen)
  })
  val idx = RegInit(0.U(log2Ceil(n).W))
  idx := idx + 1.U

  io.out := io.in(idx)
}

これは不思議なことに、GenBundleOutput / Inputの属性を付属させなかった場合は動作しない。

...
[error] (run-main-0) chisel3.core.Binding$RebindingException: Attempted reassignment of binding to chisel3.core.UInt@0
[error] chisel3.core.Binding$RebindingException: Attempted reassignment of binding to chisel3.core.UInt@0
...

また、GenBundleの属性をInputに設定しても動作しない。

class GenBundle[T <: Data](dataType: T) extends Bundle {
  override def cloneType: this.type =
    new GenBundle(dataType).asInstanceOf[this.type]

  // Inputでは正しく生成できない。
  val valid    = Input(Bool())
  val sideband = Input(UInt(10.W))
  val data     = Input(dataType)
}
[error] firrtl.passes.CheckInitialization$RefNotInitializedException:  @[:@6.4] : [module GenericArbiter]  Reference io is not fully initialized.
[error]    : io.in[1].valid <= VOID
[error] firrtl.passes.CheckInitialization$RefNotInitializedException:  @[:@6.4] : [module GenericArbiter]  Reference io is not fully initialized.
[error]    : io.in[1].data <= VOID
[error] firrtl.passes.CheckInitialization$RefNotInitializedException:  @[:@6.4] : [module GenericArbiter]  Reference io is not fully initialized.

以下の構成だと正しくVerilogが生成できる。

class GenBundle[T <: Data](dataType: T) extends Bundle {
  override def cloneType: this.type =
    new GenBundle(dataType).asInstanceOf[this.type]

  val valid    = Output(Bool())
  val sideband = Output(UInt(10.W))
  val data     = Output(dataType)
}

class GenericArbiter[T <: Data](val gen:T, val n: Int) extends Module {
  // val io = IO(new ArbiterIO(gen, n))
  val io = IO(new Bundle {
    val in = Input(Vec(n, gen))
    val out = Output(gen)
  })

  val idx = RegInit(0.U(log2Ceil(n).W))
  idx := idx + 1.U

  io.out := io.in(idx)
}

あるいは、Input/Outputを1つにまとめてArbiterとしてI/Oを宣言する手法もある。 `

class GenBundle[T <: Data](dataType: T) extends Bundle {
  override def cloneType: this.type =
    new GenBundle(dataType).asInstanceOf[this.type]

  val valid    = Output(Bool())
  val sideband = Output(UInt(10.W))
  val data     = Output(dataType)
}

class ArbiterIO[T <: Data](val gen: T, val n: Int) extends Bundle {
  val in  = Flipped(Vec(n, gen))
  val out = gen
}


class GenericArbiter[T <: Data](val gen:T, val n: Int) extends Module {
  val io = IO(new ArbiterIO(gen, n))

  val idx = RegInit(0.U(log2Ceil(n).W))
  idx := idx + 1.U

  io.out := io.in(idx)
}