Skip to content

Commit

Permalink
[util] Add a withShadowLayer Queue
Browse files Browse the repository at this point in the history
Add a method to the `Queue$` object that can be used to create a `Queue`
and include a second queue that contains some data which will be tracked
alongside the first `Queue`, but this will be kept in a layer.

This is added to help address a use case where design verification wants
to track some extra, sidecar data that should be added to some data
pipeline.  However, this sidecar data is expected to be removed from the
design.  This would normally be addressed with a generator-time parameter.
However, the generator-time parameter prevents removal of the sidecar data
unless the design is re-elaborated.

Signed-off-by: Schuyler Eldridge <[email protected]>
  • Loading branch information
seldridge committed Jan 3, 2025
1 parent e45609e commit d6e7701
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
21 changes: 21 additions & 0 deletions integration-tests/src/test/scala/chiselTest/QueueSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -303,4 +303,25 @@ class QueueSpec extends ChiselPropSpec {
chirrtl should include("inst foo_q of Queue")
chirrtl should include("inst bar_q of Queue")
}

property("A shadow queue should track an identifier") {
class Foo extends Module {
val in = IO(Flipped(Decoupled(UInt(8.W))))
val out = IO(Decoupled(UInt(8.W)))
val outShadow = IO(probe.Probe(Valid(UInt(4.W)), layers.Verification))

private val id = Wire(probe.Probe(UInt(4.W), layers.Verification))
layer.block(layers.Verification) {
val (_id, _) = Counter(in.fire, 15)
probe.define(id, probe.ProbeValue(_id))
}

private val (queue, shadow) = Queue.withShadowLayer(enq = in, layerDataTuple = (probe.read(id), layers.Verification))
out :<>= queue
probe.define(outShadow, shadow)
}

println(ChiselStage.emitCHIRRTL(new Foo))
println(ChiselStage.emitSystemVerilog(new Foo, firtoolOpts=Array("-disable-all-randomization", "-strip-debug-info", "-enable-layers=Verification.Assert", "-enable-layers=Verification.Assume", "-enable-layers=Verification.Cover")))
}
}
33 changes: 33 additions & 0 deletions src/main/scala/chisel3/util/Queue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package chisel3.util

import chisel3._
import chisel3.experimental.requireIsChiselType
import chisel3.layer.{block, Layer}
import chisel3.probe.{define, Probe, ProbeValue}

/** An I/O Bundle for Queues
* @param gen The type of data to queue
Expand Down Expand Up @@ -185,6 +187,37 @@ object Queue {
}
}

def withShadowLayer[T <: Data, S <: Data](
enq: ReadyValidIO[T],
entries: Int = 2,
pipe: Boolean = false,
flow: Boolean = false,
useSyncReadMem: Boolean = false,
flush: Option[Bool] = None,
layerDataTuple: (S, layer.Layer)
): (DecoupledIO[T], Valid[S]) = {
val queue = apply(enq, entries, pipe, flow, useSyncReadMem, flush)

val (data, layer) = layerDataTuple
val shadowDeq = Wire(Probe(Valid(chiselTypeOf(data)), layer))
block(layer) {
val shadowEnq = Wire(Decoupled(chiselTypeOf(data)))
shadowEnq.ready :<= true.B
shadowEnq.valid :<= enq.fire
shadowEnq.bits :<= data

val shadowQueue = Queue(shadowEnq, entries, pipe, flow, useSyncReadMem, flush)

val _shadowDeq = Wire(Valid(chiselTypeOf(data)))
_shadowDeq.valid :<= shadowQueue.valid
_shadowDeq.bits :<= shadowQueue.bits
shadowQueue.ready :<= queue.ready
define(shadowDeq, ProbeValue(_shadowDeq))
}

(queue, shadowDeq)
}

/** Create a queue and supply a [[IrrevocableIO]] containing the product.
* Casting from [[DecoupledIO]] is safe here because we know the [[Queue]] has
* Irrevocable semantics.
Expand Down

0 comments on commit d6e7701

Please sign in to comment.