Chiselによりインタフェースのパラメタライズの検討を行う。例えば、汎用インタフェースを使用してバスのマルチプレクサを構成することを考える。
インタフェースとしては以下のものを使う。以下のGenBundle
はT
で汎用化されている。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) }
これは不思議なことに、GenBundle
にOutput / 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) }