Gowin Vol.3 第2部第4章 リスト3

/**
* width: 音声データのビット数
* channels: チャネル数
* defaultValue: デフォルト値
* interval: サンプリング周期
*/
class AudioSampler(val width: Int, val channels: Int, val defaultValue: BigInt, val interval: Int) extends Module {
if(width <= 0 ) {
throw new IllegalArgumentException("width must be greater than 0")
}
if(channels <= 0 ) {
throw new IllegalArgumentException("channels must be greater than 0")
}

val io = IO(new Bundle {
val dataIn = Vec(channels, Flipped(Decoupled(UInt((width*2).W))))
val dataOut = Vec(channels, Decoupled(UInt((width*2).W)))
})

val counter = RegInit(0.U(log2Ceil(interval).W))

val dataOutValid = RegInit(VecInit((0 until channels).map(_ => false.B)))
val dataOutBits = RegInit(VecInit((0 until channels).map(_ => 0.U((width*2).W))))
val channelDefaultValue = Cat(defaultValue.U(width.W), defaultValue.U(width.W))

for(ch <- 0 until channels) {
io.dataIn(ch).ready := counter === 0.U // サンプリング周期でのみ入力を受け付ける
io.dataOut(ch).bits := dataOutBits(ch)
io.dataOut(ch).valid := dataOutValid(ch)
when( io.dataOut(ch).fire ) {
dataOutValid(ch) := false.B
}
}

// 指定した周期で入力をサンプリング
when(counter === 0.U) {
for(ch <- 0 until channels) {
when(!dataOutValid(ch) || io.dataOut(ch).ready) { // 出力可能であれば出力
// 入力データが無ければデフォルト値を出力する
dataOutValid(ch) := true.B
dataOutBits(ch) := Mux(io.dataIn(ch).valid, io.dataIn(ch).bits, channelDefaultValue)
}
}
counter := (interval - 1).U
} .otherwise {
counter := counter - 1.U
}
}