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

/**
* width: バッファのデータ幅
* entries: バッファの最大エントリ数
* threshold: 出力開始するまで蓄えるエントリ数
*/
class AudioBuffer(val width: Int, val entries: Int, val threshold: Int) extends Module {
if(threshold > entries) {
throw new IllegalArgumentException("threshold must be less than or equal to entries")
}
if(entries <= 0 ) {
throw new IllegalArgumentException("entries must be greater than 0")
}
if(width <= 0 ) {
throw new IllegalArgumentException("width must be greater than 0")
}

val counterBits = log2Ceil(entries + 1)

val io = IO(new Bundle {
val dataIn = Flipped(Decoupled(UInt(width.W)))
val dataOut = Decoupled(UInt(width.W))
val buffering = Output(Bool()) // バッファに蓄えている間はtrue
val bufferedEntries = Output(UInt(counterBits.W)) // バッファ内の現在のエントリ数
})

val bufferOut = Queue(io.dataIn, entries)
val buffering = RegInit(true.B)
val bufferedEntries = RegInit(0.U(counterBits.W))

io.dataOut.valid := bufferOut.valid && !buffering
bufferOut.ready := io.dataOut.ready && !buffering
io.dataOut.bits := bufferOut.bits

io.buffering := buffering
io.bufferedEntries := bufferedEntries

when( io.dataIn.fire && !io.dataOut.fire ) {
bufferedEntries := bufferedEntries + 1.U
} .elsewhen( !io.dataIn.fire && io.dataOut.fire ) {
bufferedEntries := bufferedEntries - 1.U
}

// バッファが空になったらバッファリングを開始(出力を停止)
when( bufferedEntries === 0.U ) {
buffering := true.B
} .elsewhen( buffering && bufferedEntries >= threshold.U ) {
// バッファ内のエントリ数が閾値を越えたら,バッファリングを停止(出力を開始)
buffering := false.B
}
}