Merge pull request #697 from ucb-bar/async_queue_option
Add narrowData option to AsyncQueue.
This commit is contained in:
		@@ -35,7 +35,7 @@ class AsyncValidSync(sync: Int, desc: String) extends Module {
 | 
				
			|||||||
  io.out := UIntSyncChain(io.in.asUInt, sync, desc)(0)
 | 
					  io.out := UIntSyncChain(io.in.asUInt, sync, desc)(0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean = true) extends Module {
 | 
					class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean = true, narrowData: Boolean = false) extends Module {
 | 
				
			||||||
  val bits = log2Ceil(depth)
 | 
					  val bits = log2Ceil(depth)
 | 
				
			||||||
  val io = new Bundle {
 | 
					  val io = new Bundle {
 | 
				
			||||||
    // These come from the source domain
 | 
					    // These come from the source domain
 | 
				
			||||||
@@ -43,7 +43,8 @@ class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean =
 | 
				
			|||||||
    // These cross to the sink clock domain
 | 
					    // These cross to the sink clock domain
 | 
				
			||||||
    val ridx = UInt(INPUT,  width = bits+1)
 | 
					    val ridx = UInt(INPUT,  width = bits+1)
 | 
				
			||||||
    val widx = UInt(OUTPUT, width = bits+1)
 | 
					    val widx = UInt(OUTPUT, width = bits+1)
 | 
				
			||||||
    val mem  = Vec(depth, gen).asOutput
 | 
					    val mem  = Vec(if(narrowData) 1 else depth, gen).asOutput
 | 
				
			||||||
 | 
					    val index = narrowData.option(UInt(INPUT, width = bits))
 | 
				
			||||||
    // Signals used to self-stabilize a safe AsyncQueue
 | 
					    // Signals used to self-stabilize a safe AsyncQueue
 | 
				
			||||||
    val sink_reset_n = Bool(INPUT)
 | 
					    val sink_reset_n = Bool(INPUT)
 | 
				
			||||||
    val ridx_valid = Bool(INPUT)
 | 
					    val ridx_valid = Bool(INPUT)
 | 
				
			||||||
@@ -65,7 +66,7 @@ class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean =
 | 
				
			|||||||
  val widx_reg = AsyncResetReg(widx, "widx_gray")
 | 
					  val widx_reg = AsyncResetReg(widx, "widx_gray")
 | 
				
			||||||
  io.widx := widx_reg
 | 
					  io.widx := widx_reg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  io.mem := mem
 | 
					  if(narrowData) io.mem(0) := mem(io.index.get) else io.mem := mem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  io.widx_valid := Bool(true)
 | 
					  io.widx_valid := Bool(true)
 | 
				
			||||||
  if (safe) {
 | 
					  if (safe) {
 | 
				
			||||||
@@ -92,7 +93,7 @@ class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean =
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean = true) extends Module {
 | 
					class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean = true, narrowData: Boolean = false) extends Module {
 | 
				
			||||||
  val bits = log2Ceil(depth)
 | 
					  val bits = log2Ceil(depth)
 | 
				
			||||||
  val io = new Bundle {
 | 
					  val io = new Bundle {
 | 
				
			||||||
    // These come from the sink domain
 | 
					    // These come from the sink domain
 | 
				
			||||||
@@ -100,7 +101,8 @@ class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean = t
 | 
				
			|||||||
    // These cross to the source clock domain
 | 
					    // These cross to the source clock domain
 | 
				
			||||||
    val ridx = UInt(OUTPUT, width = bits+1)
 | 
					    val ridx = UInt(OUTPUT, width = bits+1)
 | 
				
			||||||
    val widx = UInt(INPUT,  width = bits+1)
 | 
					    val widx = UInt(INPUT,  width = bits+1)
 | 
				
			||||||
    val mem  = Vec(depth, gen).asInput
 | 
					    val mem  = Vec(if(narrowData) 1 else depth, gen).asInput
 | 
				
			||||||
 | 
					    val index = narrowData.option(UInt(OUTPUT, width = bits))
 | 
				
			||||||
    // Signals used to self-stabilize a safe AsyncQueue
 | 
					    // Signals used to self-stabilize a safe AsyncQueue
 | 
				
			||||||
    val source_reset_n = Bool(INPUT)
 | 
					    val source_reset_n = Bool(INPUT)
 | 
				
			||||||
    val ridx_valid = Bool(OUTPUT)
 | 
					    val ridx_valid = Bool(OUTPUT)
 | 
				
			||||||
@@ -117,11 +119,12 @@ class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean = t
 | 
				
			|||||||
  // On an FPGA, only one input changes at a time => mem updates don't cause glitches
 | 
					  // 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
 | 
					  // 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))
 | 
					  val index = if (depth == 1) UInt(0) else ridx(bits-1, 0) ^ (ridx(bits, bits) << (bits-1))
 | 
				
			||||||
 | 
					  if(narrowData) io.index.get := index
 | 
				
			||||||
  // 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.
 | 
				
			||||||
  // It is possible that bits latches when the source domain is reset / has power cut
 | 
					  // 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
 | 
					  // This is safe, because isolation gates brought mem low before the zeroed widx reached us
 | 
				
			||||||
  io.deq.bits  := RegEnable(io.mem(index), valid)
 | 
					  io.deq.bits  := RegEnable(io.mem(if(narrowData) UInt(0) else index), valid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val valid_reg = AsyncResetReg(valid.asUInt, "valid_reg")(0)
 | 
					  val valid_reg = AsyncResetReg(valid.asUInt, "valid_reg")(0)
 | 
				
			||||||
  io.deq.valid := valid_reg && source_ready
 | 
					  io.deq.valid := valid_reg && source_ready
 | 
				
			||||||
@@ -154,13 +157,16 @@ class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int, safe: Boolean = t
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3, safe: Boolean = true) extends Crossing[T] {
 | 
					// 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] {
 | 
				
			||||||
  require (sync >= 2)
 | 
					  require (sync >= 2)
 | 
				
			||||||
  require (depth > 0 && isPow2(depth))
 | 
					  require (depth > 0 && isPow2(depth))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val io = new CrossingIO(gen)
 | 
					  val io = new CrossingIO(gen)
 | 
				
			||||||
  val source = Module(new AsyncQueueSource(gen, depth, sync, safe))
 | 
					  val source = Module(new AsyncQueueSource(gen, depth, sync, safe, narrowData))
 | 
				
			||||||
  val sink   = Module(new AsyncQueueSink  (gen, depth, sync, safe))
 | 
					  val sink   = Module(new AsyncQueueSink  (gen, depth, sync, safe, narrowData))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  source.clock := io.enq_clock
 | 
					  source.clock := io.enq_clock
 | 
				
			||||||
  source.reset := io.enq_reset
 | 
					  source.reset := io.enq_reset
 | 
				
			||||||
@@ -174,6 +180,7 @@ class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3, safe: Boolean
 | 
				
			|||||||
  io.deq <> sink.io.deq
 | 
					  io.deq <> sink.io.deq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sink.io.mem := source.io.mem
 | 
					  sink.io.mem := source.io.mem
 | 
				
			||||||
 | 
					  if(narrowData) source.io.index.get <> sink.io.index.get
 | 
				
			||||||
  sink.io.widx := source.io.widx
 | 
					  sink.io.widx := source.io.widx
 | 
				
			||||||
  source.io.ridx := sink.io.ridx
 | 
					  source.io.ridx := sink.io.ridx
 | 
				
			||||||
  sink.io.widx_valid := source.io.widx_valid
 | 
					  sink.io.widx_valid := source.io.widx_valid
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user