async_queue: Give names to all the registers which show up in the queue (#390)
This is to aid debugging but even more so for backend constraint writers, who generally need predictable names for registers to set false paths, etc.
This commit is contained in:
parent
4fd03ffdf1
commit
a84a961a39
@ -72,15 +72,15 @@ class RegisterWriteCrossing[T <: Data](gen: T, sync: Int = 3) extends Module {
|
|||||||
// If the slave is not operational, just drop the write.
|
// If the slave is not operational, just drop the write.
|
||||||
val progress = crossing.io.enq.ready || !io.master_allow
|
val progress = crossing.io.enq.ready || !io.master_allow
|
||||||
|
|
||||||
val reg = Module(new BusyRegisterCrossing(io.master_clock, io.master_reset))
|
val control = Module(new BusyRegisterCrossing(io.master_clock, io.master_reset))
|
||||||
reg.io.progress := progress
|
control.io.progress := progress
|
||||||
reg.io.request_valid := io.master_port.request.valid
|
control.io.request_valid := io.master_port.request.valid
|
||||||
reg.io.response_ready := io.master_port.response.ready
|
control.io.response_ready := io.master_port.response.ready
|
||||||
|
|
||||||
crossing.io.deq.ready := Bool(true)
|
crossing.io.deq.ready := Bool(true)
|
||||||
crossing.io.enq.valid := io.master_port.request.valid && !reg.io.busy
|
crossing.io.enq.valid := io.master_port.request.valid && !control.io.busy
|
||||||
io.master_port.request.ready := progress && !reg.io.busy
|
io.master_port.request.ready := progress && !control.io.busy
|
||||||
io.master_port.response.valid := progress && reg.io.busy
|
io.master_port.response.valid := progress && control.io.busy
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegField should support connecting to one of these
|
// RegField should support connecting to one of these
|
||||||
@ -121,14 +121,14 @@ class RegisterReadCrossing[T <: Data](gen: T, sync: Int = 3) extends Module {
|
|||||||
// If the slave is not operational, just repeat the last value we saw.
|
// If the slave is not operational, just repeat the last value we saw.
|
||||||
val progress = crossing.io.deq.valid || !io.master_allow
|
val progress = crossing.io.deq.valid || !io.master_allow
|
||||||
|
|
||||||
val reg = Module(new BusyRegisterCrossing(io.master_clock, io.master_reset))
|
val control = Module(new BusyRegisterCrossing(io.master_clock, io.master_reset))
|
||||||
reg.io.progress := progress
|
control.io.progress := progress
|
||||||
reg.io.request_valid := io.master_port.request.valid
|
control.io.request_valid := io.master_port.request.valid
|
||||||
reg.io.response_ready := io.master_port.response.ready
|
control.io.response_ready := io.master_port.response.ready
|
||||||
|
|
||||||
io.master_port.response.valid := progress && reg.io.busy
|
io.master_port.response.valid := progress && control.io.busy
|
||||||
io.master_port.request.ready := progress && !reg.io.busy
|
io.master_port.request.ready := progress && !control.io.busy
|
||||||
crossing.io.deq.ready := io.master_port.request.valid && !reg.io.busy
|
crossing.io.deq.ready := io.master_port.request.valid && !control.io.busy
|
||||||
crossing.io.enq.valid := Bool(true)
|
crossing.io.enq.valid := Bool(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,17 +4,19 @@ package util
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
||||||
object GrayCounter {
|
object GrayCounter {
|
||||||
def apply(bits: Int, increment: Bool = Bool(true)): UInt = {
|
def apply(bits: Int, increment: Bool = Bool(true), name: String = "binary"): UInt = {
|
||||||
val incremented = Wire(UInt(width=bits))
|
val incremented = Wire(UInt(width=bits))
|
||||||
val binary = AsyncResetReg(incremented, 0)
|
val binary = AsyncResetReg(incremented, name)
|
||||||
incremented := binary + increment.asUInt()
|
incremented := binary + increment.asUInt()
|
||||||
incremented ^ (incremented >> UInt(1))
|
incremented ^ (incremented >> UInt(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object AsyncGrayCounter {
|
object AsyncGrayCounter {
|
||||||
def apply(in: UInt, sync: Int): UInt = {
|
def apply(in: UInt, sync: Int, name: String = "gray"): UInt = {
|
||||||
val syncv = List.fill(sync)(Module (new AsyncResetRegVec(w = in.getWidth, 0)))
|
val syncv = List.tabulate(sync)(i =>
|
||||||
|
Module (new AsyncResetRegVec(w = in.getWidth, 0)).suggestName(s"${name}_sync_${i}")
|
||||||
|
)
|
||||||
syncv.last.io.d := in
|
syncv.last.io.d := in
|
||||||
syncv.last.io.en := Bool(true)
|
syncv.last.io.en := Bool(true)
|
||||||
(syncv.init zip syncv.tail).foreach { case (sink, source) =>
|
(syncv.init zip syncv.tail).foreach { case (sink, source) =>
|
||||||
@ -37,16 +39,16 @@ class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int) extends Module
|
|||||||
}
|
}
|
||||||
|
|
||||||
val mem = Reg(Vec(depth, gen)) //This does NOT need to be asynchronously reset.
|
val mem = Reg(Vec(depth, gen)) //This does NOT need to be asynchronously reset.
|
||||||
val widx = GrayCounter(bits+1, io.enq.fire())
|
val widx = GrayCounter(bits+1, io.enq.fire(), "widx_bin")
|
||||||
val ridx = AsyncGrayCounter(io.ridx, sync)
|
val ridx = AsyncGrayCounter(io.ridx, sync, "ridx_gray")
|
||||||
val ready = widx =/= (ridx ^ UInt(depth | depth >> 1))
|
val ready = widx =/= (ridx ^ UInt(depth | depth >> 1))
|
||||||
|
|
||||||
val index = if (depth == 1) UInt(0) else io.widx(bits-1, 0) ^ (io.widx(bits, bits) << (bits-1))
|
val index = if (depth == 1) UInt(0) else io.widx(bits-1, 0) ^ (io.widx(bits, bits) << (bits-1))
|
||||||
when (io.enq.fire() && !reset) { mem(index) := io.enq.bits }
|
when (io.enq.fire()) { mem(index) := io.enq.bits }
|
||||||
val ready_reg = AsyncResetReg(ready, 0)
|
val ready_reg = AsyncResetReg(ready, "ready")
|
||||||
io.enq.ready := ready_reg
|
io.enq.ready := ready_reg
|
||||||
|
|
||||||
val widx_reg = AsyncResetReg(widx, 0)
|
val widx_reg = AsyncResetReg(widx, "widx_gray")
|
||||||
io.widx := widx_reg
|
io.widx := widx_reg
|
||||||
|
|
||||||
io.mem := mem
|
io.mem := mem
|
||||||
@ -63,8 +65,8 @@ class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int) extends Module {
|
|||||||
val mem = Vec(depth, gen).asInput
|
val mem = Vec(depth, gen).asInput
|
||||||
}
|
}
|
||||||
|
|
||||||
val ridx = GrayCounter(bits+1, io.deq.fire())
|
val ridx = GrayCounter(bits+1, io.deq.fire(), "ridx_bin")
|
||||||
val widx = AsyncGrayCounter(io.widx, sync)
|
val widx = AsyncGrayCounter(io.widx, sync, "widx_gray")
|
||||||
val valid = ridx =/= widx
|
val valid = ridx =/= widx
|
||||||
|
|
||||||
// The mux is safe because timing analysis ensures ridx has reached the register
|
// The mux is safe because timing analysis ensures ridx has reached the register
|
||||||
@ -74,11 +76,12 @@ class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int) extends Module {
|
|||||||
val index = if (depth == 1) UInt(0) else ridx(bits-1, 0) ^ (ridx(bits, bits) << (bits-1))
|
val index = if (depth == 1) UInt(0) else ridx(bits-1, 0) ^ (ridx(bits, bits) << (bits-1))
|
||||||
// This register does not NEED to be reset, as its contents will not
|
// This register does not NEED to be reset, as its contents will not
|
||||||
// be considered unless the asynchronously reset deq valid register is set.
|
// be considered unless the asynchronously reset deq valid register is set.
|
||||||
io.deq.bits := RegEnable(io.mem(index), valid)
|
val data = RegEnable(io.mem(index), valid)
|
||||||
|
io.deq.bits := data
|
||||||
|
|
||||||
io.deq.valid := AsyncResetReg(valid, 0)
|
io.deq.valid := AsyncResetReg(valid, "valid_reg")
|
||||||
|
|
||||||
io.ridx := AsyncResetReg(ridx, 0)
|
io.ridx := AsyncResetReg(ridx, "ridx_gray")
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3) extends Crossing[T] {
|
class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3) extends Crossing[T] {
|
||||||
|
Loading…
Reference in New Issue
Block a user