Skip to content

Commit

Permalink
[rtl] complete stdlib Queue and add "almost" ports
Browse files Browse the repository at this point in the history
Signed-off-by: unlsycn <[email protected]>
  • Loading branch information
unlsycn committed Oct 31, 2024
1 parent c70556b commit 0da76cb
Showing 1 changed file with 85 additions and 56 deletions.
141 changes: 85 additions & 56 deletions stdlib/src/Queue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import org.chipsalliance.dwbb.interface.DW_fifo_s1_sf.{Interface => DwbbFifoInte
import chisel3.ltl.AssertProperty
import chisel3.util.{Decoupled, DecoupledIO, DeqIO, EnqIO, ReadyValidIO}

class QueueIO[T <: Data](private val gen: T) extends Bundle {
class QueueIO[T <: Data](private val gen: T, entries: Int) extends Bundle {
val enq = Flipped(EnqIO(gen))
val deq = Flipped(DeqIO(gen))

val empty = Output(Bool())
val full = Output(Bool())
val empty = Output(Bool())
val full = Output(Bool())
val almostEmpty = if (entries >= 2) Some(Output(Bool())) else None
val almostFull = if (entries >= 2) Some(Output(Bool())) else None
}

object Queue {
Expand All @@ -23,79 +25,106 @@ object Queue {
flow: Boolean = false,
resetMem: Boolean = false
): DecoupledIO[T] = {

val io = this.io(chiselTypeOf(enq.bits), entries, pipe, flow, resetMem)
io.enq <> enq

io.deq
}

def io[T <: Data](
gen: T,
entries: Int = 2,
pipe: Boolean = false,
flow: Boolean = false,
resetMem: Boolean = false
gen: T,
entries: Int = 2,
pipe: Boolean = false,
flow: Boolean = false,
resetMem: Boolean = false,
almostEmptyLevel: Int = 1,
almostFullLevel: Int = 1
): QueueIO[T] = {
require(gen.getWidth <= 2048, "Data width must be less than 2048")
require(entries <= 1024, "Entries must be less than 1024")

val clock = Module.clock
val reset = Module.reset

val io = Wire(new QueueIO(gen))
require(
Range.inclusive(1, 2048).contains(gen.getWidth),
"Data width must be between 1 and 2048"
)
require(
Range.inclusive(1, 1024).contains(entries),
"Entries must be between 1 and 1024"
)

if (entries < 2) {
val queue = Module(new chisel3.util.Queue(gen, entries, pipe, flow))
queue.io.enq <> io.enq
queue.io.deq <> io.deq
io.empty := queue.io.count === 0.U
io.full := queue.io.count === entries.U
val io = Wire(new QueueIO(gen, entries))

return io
}
if (entries >= 2) {
require(
Range.inclusive(1, entries - 1).contains(almostEmptyLevel),
"almost empty level must be between 1 and entries-1"
)
require(
Range.inclusive(1, entries - 1).contains(almostFullLevel),
"almost full level must be between 1 and entries-1"
)

// TODO: use sync reset for now and wait for t1 to migrate to FixedIOModule
// require(reset.typeName == "Bool" || reset.typeName == "AsyncReset")
val useAsyncReset = reset.typeName == "AsyncReset"

val fifo = Instantiate(
new DwbbFifo(
new DwbbFifoParameter(
width = gen.getWidth,
depth = entries,
errMode = "unlatched",
rstMode = (useAsyncReset, resetMem) match {
case (false, false) => "sync_wo_mem"
case (false, true) => "sync_with_mem"
case (true, false) => "async_wo_mem"
case (true, true) => "async_with_mem"
}
val clock = Module.clock
val reset = Module.reset

// TODO: use sync reset for now and wait for t1 to migrate to FixedIOModule
// require(reset.typeName == "Bool" || reset.typeName == "AsyncReset")
val useAsyncReset = reset.typeName == "AsyncReset"

val fifo = Instantiate(
new DwbbFifo(
new DwbbFifoParameter(
width = gen.getWidth,
depth = entries,
errMode = "unlatched",
rstMode = (useAsyncReset, resetMem) match {
case (false, false) => "sync_wo_mem"
case (false, true) => "sync_with_mem"
case (true, false) => "async_wo_mem"
case (true, true) => "async_with_mem"
}
)
)
)
)

val dataIn = io.enq.bits.asUInt
val dataOut = fifo.io.data_out.asTypeOf(io.deq.bits)
val dataIn = io.enq.bits.asUInt
val dataOut = fifo.io.data_out.asTypeOf(io.deq.bits)

fifo.io.clk := clock
fifo.io.rst_n := ~(reset.asBool)

fifo.io.clk := clock
fifo.io.rst_n := ~(reset.asBool)
fifo.io.diag_n := ~(false.B)

fifo.io.diag_n := ~(false.B)
io.enq.ready := !fifo.io.full || (if (pipe) io.deq.ready else false.B)
fifo.io.push_req_n := ~(io.enq.fire && (if (flow) !(fifo.io.empty && io.deq.ready) else true.B))
fifo.io.data_in := dataIn

io.enq.ready := !fifo.io.full || (if (pipe) io.deq.ready else false.B)
fifo.io.push_req_n := ~(io.enq.fire && (if (flow) !(fifo.io.empty && io.deq.ready) else true.B))
fifo.io.data_in := dataIn
io.deq.valid := !fifo.io.empty || (if (flow) io.enq.valid else false.B)
fifo.io.pop_req_n := ~(io.deq.ready && !fifo.io.empty)
io.deq.bits := (if (flow) Mux(fifo.io.empty, io.enq.bits, dataOut) else dataOut)

io.deq.valid := !fifo.io.empty || (if (flow) io.enq.valid else false.B)
fifo.io.pop_req_n := ~(io.deq.ready && !fifo.io.empty)
io.deq.bits := (if (flow) Mux(fifo.io.empty, io.enq.bits, dataOut) else dataOut)
io.empty := fifo.io.empty
io.full := fifo.io.full
io.almostEmpty.get := fifo.io.almost_empty
io.almostFull.get := fifo.io.almost_full

io.empty := fifo.io.empty
io.full := fifo.io.full
// There should be no error since we guarantee to push/pop items only when the fifo is neither empty nor full.
AssertProperty(!fifo.io.error)
} else {
val data = Reg(gen)
val empty = RegInit(true.B)
val full = !empty

// There should be no error since we guarantee to push/pop items only when the fifo is neither empty nor full.
AssertProperty(!fifo.io.error)
val push = io.enq.fire && (if (flow) !(empty && io.deq.ready) else true.B)
io.enq.ready := empty || (if (pipe) io.deq.ready else false.B)
data := Mux(push, io.enq.bits, data)

val pop = io.deq.ready && full
io.deq.valid := full || (if (flow) io.enq.valid else false.B)
io.deq.bits := (if (flow) Mux(empty, io.enq.bits, data) else data)

empty := Mux(push =/= pop, pop, empty)

io.empty := empty
io.full := full
}

io
}
Expand Down

0 comments on commit 0da76cb

Please sign in to comment.