Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DelayQueue #3520

Merged
merged 2 commits into from
Nov 7, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions src/main/scala/util/DelayQueue.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.util

import chisel3._
import chisel3.util._

/** A queue that delays elements by a certain cycle count.
*
* @param gen queue element type
* @param entries queue size
*
* @param enq enqueue
* @param deq dequeue
* @param timer cycle count timer
* @param entries cycle delay
*/
class DelayQueue[T <: Data](gen: T, entries: Int) extends Module {
val io = IO(new Bundle {
val enq = Flipped(DecoupledIO(gen))
val deq = DecoupledIO(gen)
val timer = Input(UInt())
val delay = Input(UInt())
})

val q = Module(new Queue(new Bundle {
val data = gen
val time = UInt(io.timer.getWidth.W)
}, entries, flow=true))

val delay_r = RegInit(0.U(io.delay.getWidth.W))
when (delay_r =/= io.delay) {
delay_r := io.delay
assert(q.io.count == 0, "Undefined behavior when delay is changed while queue has elements.")
}

q.io.enq.bits.data := io.enq.bits
q.io.enq.bits.time := io.timer
q.io.enq.valid := io.enq.fire
io.enq.ready := q.io.enq.ready

io.deq.bits := q.io.deq.bits.data
io.deq.valid := q.io.deq.valid && ((io.timer - q.io.deq.bits.time) >= delay_r)
q.io.deq.ready := io.deq.fire
}

object DelayQueue {
/** Helper to connect a delay queue.
*
* @param source decoupled queue input
* @param timer cycle count timer
* @param delay cycle delay
* @param depth queue size
*/
def apply[T <: Data](source: DecoupledIO[T], timer: UInt, delay: UInt, depth: Int): DecoupledIO[T] = {
val delayQueue = Module(new DelayQueue(chiselTypeOf(source.bits), depth))
delayQueue.io.enq <> source
delayQueue.io.timer := timer
delayQueue.io.delay := delay
delayQueue.io.deq
}

/** Helper to connect a delay queue and instantiate a timer to keep track of cycle count.
*
* @param source decoupled queue input
* @param timerWidth width of cycle count timer
* @param delay cycle delay
* @param depth queue size
*/
def apply[T <: Data](source: DecoupledIO[T], timerWidth: Int, delay: UInt, depth: Int): DecoupledIO[T] = {
val timer = RegInit(0.U(timerWidth.W))
timer := timer + 1.U
abejgonzalez marked this conversation as resolved.
Show resolved Hide resolved
apply(source, timer, delay, depth)
}

/** Helper to connect a delay queue that delays elements by a statically defined cycle count.
*
* @param source decoupled queue input
* @param delay static cycle delay
*/
def apply[T <: Data](source: DecoupledIO[T], delay: Int): DecoupledIO[T] = {
val mDelay = delay.max(1)
apply(source, (1 + log2Ceil(mDelay)), delay.U, mDelay)
}

/** Helper to connect a delay queue that delays elements by a dynamically set cycle count.
*
* @param source decoupled queue input
* @param delay cycle delay
* @param maxDelay maximum cycle delay
*/
def apply[T <: Data](source: DecoupledIO[T], delay: UInt, maxDelay: Int = 4096): DecoupledIO[T] = {
val mDelay = maxDelay.max(1)
apply(source, (1 + log2Ceil(mDelay)), delay, mDelay)
}
}