2016-11-28 01:16:37 +01:00
|
|
|
// See LICENSE.SiFive for license details.
|
2016-09-14 00:30:09 +02:00
|
|
|
|
2017-07-07 19:48:16 +02:00
|
|
|
package freechips.rocketchip.util
|
|
|
|
|
2016-09-14 00:30:09 +02:00
|
|
|
import Chisel._
|
|
|
|
|
|
|
|
object GrayCounter {
|
2016-10-09 05:25:19 +02:00
|
|
|
def apply(bits: Int, increment: Bool = Bool(true), clear: Bool = Bool(false), name: String = "binary"): UInt = {
|
2016-09-26 20:08:38 +02:00
|
|
|
val incremented = Wire(UInt(width=bits))
|
2016-10-09 05:25:19 +02:00
|
|
|
val binary = AsyncResetReg(incremented, name)
|
2016-10-07 07:31:42 +02:00
|
|
|
incremented := Mux(clear, UInt(0), binary + increment.asUInt())
|
2016-09-14 00:30:09 +02:00
|
|
|
incremented ^ (incremented >> UInt(1))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-15 03:05:35 +02:00
|
|
|
class AsyncValidSync(sync: Int, desc: String) extends Module {
|
|
|
|
val io = new Bundle {
|
|
|
|
val in = Bool(INPUT)
|
|
|
|
val out = Bool(OUTPUT)
|
|
|
|
}
|
2017-08-25 02:34:07 +02:00
|
|
|
io.out := AsyncResetSynchronizerShiftReg(io.in, sync, Some(desc))
|
2016-10-15 03:05:35 +02:00
|
|
|
}
|
|
|
|
|
2017-04-22 01:31:17 +02:00
|
|
|
class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean = true, narrowData: Boolean = false) extends Module {
|
2016-09-14 00:30:09 +02:00
|
|
|
val bits = log2Ceil(depth)
|
|
|
|
val io = new Bundle {
|
|
|
|
// These come from the source domain
|
2016-10-07 05:41:21 +02:00
|
|
|
val enq = Decoupled(gen).flip
|
2016-09-14 00:30:09 +02:00
|
|
|
// These cross to the sink clock domain
|
|
|
|
val ridx = UInt(INPUT, width = bits+1)
|
|
|
|
val widx = UInt(OUTPUT, width = bits+1)
|
2017-04-22 01:31:17 +02:00
|
|
|
val mem = Vec(if(narrowData) 1 else depth, gen).asOutput
|
|
|
|
val index = narrowData.option(UInt(INPUT, width = bits))
|
2016-10-15 03:05:35 +02:00
|
|
|
// Signals used to self-stabilize a safe AsyncQueue
|
|
|
|
val sink_reset_n = Bool(INPUT)
|
|
|
|
val ridx_valid = Bool(INPUT)
|
|
|
|
val widx_valid = Bool(OUTPUT)
|
2016-09-14 00:30:09 +02:00
|
|
|
}
|
|
|
|
|
2016-10-15 03:05:35 +02:00
|
|
|
val sink_ready = Wire(init = Bool(true))
|
|
|
|
val mem = Reg(Vec(depth, gen)) // This does NOT need to be reset at all.
|
|
|
|
val widx = GrayCounter(bits+1, io.enq.fire(), !sink_ready, "widx_bin")
|
2017-08-25 02:34:07 +02:00
|
|
|
val ridx = AsyncResetSynchronizerShiftReg(io.ridx, sync, Some("ridx_gray"))
|
2016-10-26 01:44:20 +02:00
|
|
|
val ready = sink_ready && widx =/= (ridx ^ UInt(depth | depth >> 1))
|
2016-09-14 00:30:09 +02:00
|
|
|
|
|
|
|
val index = if (depth == 1) UInt(0) else io.widx(bits-1, 0) ^ (io.widx(bits, bits) << (bits-1))
|
2016-10-07 05:42:51 +02:00
|
|
|
when (io.enq.fire()) { mem(index) := io.enq.bits }
|
2016-10-07 05:27:34 +02:00
|
|
|
|
2016-10-09 05:32:08 +02:00
|
|
|
val ready_reg = AsyncResetReg(ready.asUInt, "ready_reg")(0)
|
2016-10-15 03:05:35 +02:00
|
|
|
io.enq.ready := ready_reg && sink_ready
|
2016-09-26 20:08:38 +02:00
|
|
|
|
2016-10-09 05:25:19 +02:00
|
|
|
val widx_reg = AsyncResetReg(widx, "widx_gray")
|
2016-09-26 20:08:38 +02:00
|
|
|
io.widx := widx_reg
|
|
|
|
|
2017-04-22 01:31:17 +02:00
|
|
|
if(narrowData) io.mem(0) := mem(io.index.get) else io.mem := mem
|
2016-10-07 07:41:27 +02:00
|
|
|
|
2016-10-15 03:05:35 +02:00
|
|
|
io.widx_valid := Bool(true)
|
|
|
|
if (safe) {
|
|
|
|
val source_valid = Module(new AsyncValidSync(sync+1, "source_valid"))
|
|
|
|
val sink_extend = Module(new AsyncValidSync(1, "sink_extend"))
|
|
|
|
val sink_valid = Module(new AsyncValidSync(sync, "sink_valid"))
|
|
|
|
source_valid.reset := reset || !io.sink_reset_n
|
|
|
|
sink_extend .reset := reset || !io.sink_reset_n
|
|
|
|
|
|
|
|
source_valid.io.in := Bool(true)
|
|
|
|
io.widx_valid := source_valid.io.out
|
|
|
|
sink_extend.io.in := io.ridx_valid
|
|
|
|
sink_valid.io.in := sink_extend.io.out
|
|
|
|
sink_ready := sink_valid.io.out
|
|
|
|
|
2016-10-26 01:44:20 +02:00
|
|
|
// Assert that if there is stuff in the queue, then reset cannot happen
|
|
|
|
// Impossible to write because dequeue can occur on the receiving side,
|
|
|
|
// then reset allowed to happen, but write side cannot know that dequeue
|
|
|
|
// occurred.
|
|
|
|
// TODO: write some sort of sanity check assertion for users
|
|
|
|
// that denote don't reset when there is activity
|
|
|
|
// assert (!(reset || !io.sink_reset_n) || !io.enq.valid, "Enque while sink is reset and AsyncQueueSource is unprotected")
|
|
|
|
// assert (!reset_rise || prev_idx_match.toBool, "Sink reset while AsyncQueueSource not empty")
|
2016-10-15 03:05:35 +02:00
|
|
|
}
|
2016-09-14 00:30:09 +02:00
|
|
|
}
|
|
|
|
|
2017-04-22 01:31:17 +02:00
|
|
|
class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean = true, narrowData: Boolean = false) extends Module {
|
2016-09-14 00:30:09 +02:00
|
|
|
val bits = log2Ceil(depth)
|
|
|
|
val io = new Bundle {
|
|
|
|
// These come from the sink domain
|
|
|
|
val deq = Decoupled(gen)
|
|
|
|
// These cross to the source clock domain
|
|
|
|
val ridx = UInt(OUTPUT, width = bits+1)
|
|
|
|
val widx = UInt(INPUT, width = bits+1)
|
2017-04-22 01:31:17 +02:00
|
|
|
val mem = Vec(if(narrowData) 1 else depth, gen).asInput
|
|
|
|
val index = narrowData.option(UInt(OUTPUT, width = bits))
|
2016-10-15 03:05:35 +02:00
|
|
|
// Signals used to self-stabilize a safe AsyncQueue
|
|
|
|
val source_reset_n = Bool(INPUT)
|
|
|
|
val ridx_valid = Bool(OUTPUT)
|
|
|
|
val widx_valid = Bool(INPUT)
|
2016-09-14 00:30:09 +02:00
|
|
|
}
|
|
|
|
|
2016-10-15 03:05:35 +02:00
|
|
|
val source_ready = Wire(init = Bool(true))
|
|
|
|
val ridx = GrayCounter(bits+1, io.deq.fire(), !source_ready, "ridx_bin")
|
2017-08-25 02:34:07 +02:00
|
|
|
val widx = AsyncResetSynchronizerShiftReg(io.widx, sync, Some("widx_gray"))
|
2016-10-26 01:44:20 +02:00
|
|
|
val valid = source_ready && ridx =/= widx
|
2016-09-14 00:30:09 +02:00
|
|
|
|
|
|
|
// The mux is safe because timing analysis ensures ridx has reached the register
|
|
|
|
// On an ASIC, changes to the unread location cannot affect the selected value
|
|
|
|
// On an FPGA, only one input changes at a time => mem updates don't cause glitches
|
|
|
|
// The register only latches when the selected valued is not being written
|
|
|
|
val index = if (depth == 1) UInt(0) else ridx(bits-1, 0) ^ (ridx(bits, bits) << (bits-1))
|
2017-04-22 01:31:17 +02:00
|
|
|
if(narrowData) io.index.get := index
|
2016-09-26 20:08:38 +02:00
|
|
|
// This register does not NEED to be reset, as its contents will not
|
|
|
|
// be considered unless the asynchronously reset deq valid register is set.
|
2016-10-07 23:21:09 +02:00
|
|
|
// It is possible that bits latches when the source domain is reset / has power cut
|
|
|
|
// This is safe, because isolation gates brought mem low before the zeroed widx reached us
|
2017-08-29 02:18:54 +02:00
|
|
|
val deq_bits_nxt = Mux(valid, io.mem(if(narrowData) UInt(0) else index), io.deq.bits)
|
|
|
|
io.deq.bits := SynchronizerShiftReg(deq_bits_nxt, sync = 1, name = Some("deq_bits_reg"))
|
2016-10-07 07:31:42 +02:00
|
|
|
|
2016-10-09 05:25:19 +02:00
|
|
|
val valid_reg = AsyncResetReg(valid.asUInt, "valid_reg")(0)
|
2016-10-15 03:05:35 +02:00
|
|
|
io.deq.valid := valid_reg && source_ready
|
2016-09-26 20:08:38 +02:00
|
|
|
|
2016-10-09 05:25:19 +02:00
|
|
|
val ridx_reg = AsyncResetReg(ridx, "ridx_gray")
|
2016-10-07 07:31:42 +02:00
|
|
|
io.ridx := ridx_reg
|
2016-10-07 07:41:27 +02:00
|
|
|
|
2016-10-15 03:05:35 +02:00
|
|
|
io.ridx_valid := Bool(true)
|
|
|
|
if (safe) {
|
|
|
|
val sink_valid = Module(new AsyncValidSync(sync+1, "sink_valid"))
|
|
|
|
val source_extend = Module(new AsyncValidSync(1, "source_extend"))
|
|
|
|
val source_valid = Module(new AsyncValidSync(sync, "source_valid"))
|
|
|
|
sink_valid .reset := reset || !io.source_reset_n
|
|
|
|
source_extend.reset := reset || !io.source_reset_n
|
|
|
|
|
|
|
|
sink_valid.io.in := Bool(true)
|
|
|
|
io.ridx_valid := sink_valid.io.out
|
|
|
|
source_extend.io.in := io.widx_valid
|
|
|
|
source_valid.io.in := source_extend.io.out
|
|
|
|
source_ready := source_valid.io.out
|
|
|
|
|
2016-10-26 01:44:20 +02:00
|
|
|
val reset_and_extend = !source_ready || !io.source_reset_n || reset
|
|
|
|
val reset_and_extend_prev = Reg(Bool(), reset_and_extend, Bool(true))
|
|
|
|
val reset_rise = !reset_and_extend_prev && reset_and_extend
|
|
|
|
val prev_idx_match = AsyncResetReg(updateData=(io.widx===io.ridx), resetData=0)
|
|
|
|
|
|
|
|
// TODO: write some sort of sanity check assertion for users
|
|
|
|
// that denote don't reset when there is activity
|
|
|
|
// assert (!reset_rise || prev_idx_match.toBool, "Source reset while AsyncQueueSink not empty")
|
2016-10-15 03:05:35 +02:00
|
|
|
}
|
2016-09-14 00:30:09 +02:00
|
|
|
}
|
|
|
|
|
2017-04-22 01:31:17 +02:00
|
|
|
// If narrowData is true then the read mux is moved to the source side of the crossing.
|
|
|
|
// This reduces the number of level shifters in the case where the clock crossing is also a voltage crossing,
|
|
|
|
// at the expense of a combinational path from the sink to the source and back to the sink.
|
|
|
|
class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3, safe: Boolean = true, narrowData: Boolean = false) extends Crossing[T] {
|
2016-09-14 00:30:09 +02:00
|
|
|
require (sync >= 2)
|
|
|
|
require (depth > 0 && isPow2(depth))
|
|
|
|
|
|
|
|
val io = new CrossingIO(gen)
|
2017-04-22 01:31:17 +02:00
|
|
|
val source = Module(new AsyncQueueSource(gen, depth, sync, safe, narrowData))
|
|
|
|
val sink = Module(new AsyncQueueSink (gen, depth, sync, safe, narrowData))
|
2016-09-30 02:12:13 +02:00
|
|
|
|
|
|
|
source.clock := io.enq_clock
|
|
|
|
source.reset := io.enq_reset
|
|
|
|
sink.clock := io.deq_clock
|
|
|
|
sink.reset := io.deq_reset
|
2016-09-14 00:30:09 +02:00
|
|
|
|
2016-10-07 05:27:34 +02:00
|
|
|
source.io.sink_reset_n := !io.deq_reset
|
|
|
|
sink.io.source_reset_n := !io.enq_reset
|
|
|
|
|
2016-09-14 00:30:09 +02:00
|
|
|
source.io.enq <> io.enq
|
|
|
|
io.deq <> sink.io.deq
|
|
|
|
|
|
|
|
sink.io.mem := source.io.mem
|
2017-04-22 01:31:17 +02:00
|
|
|
if(narrowData) source.io.index.get <> sink.io.index.get
|
2016-09-14 00:30:09 +02:00
|
|
|
sink.io.widx := source.io.widx
|
|
|
|
source.io.ridx := sink.io.ridx
|
2016-10-15 03:05:35 +02:00
|
|
|
sink.io.widx_valid := source.io.widx_valid
|
|
|
|
source.io.ridx_valid := sink.io.ridx_valid
|
2016-09-14 00:30:09 +02:00
|
|
|
}
|