diff options
| author | Jim Lawson | 2016-09-15 09:54:20 -0700 |
|---|---|---|
| committer | Jim Lawson | 2016-09-15 09:54:20 -0700 |
| commit | 36f77e86bbf1f471b158f36deae6a14f1d623075 (patch) | |
| tree | 9b0060b03aa9c048645b0f624598adc93088d40e /src/main/scala/chisel3/util | |
| parent | 19f5b7c6841bda318288990e643eb02fa22a49e2 (diff) | |
| parent | 2ff229dac5f915e7f583cbf9cc8118674a4e52a5 (diff) | |
Merge branch 'master' into gsdt
Diffstat (limited to 'src/main/scala/chisel3/util')
| -rw-r--r-- | src/main/scala/chisel3/util/Decoupled.scala | 94 |
1 files changed, 80 insertions, 14 deletions
diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 5ce2583c..d178cec5 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -8,13 +8,17 @@ package chisel3.util import chisel3._ import chisel3.NotStrict.CompileOptions -/** An I/O Bundle with simple handshaking using valid and ready signals for data 'bits'*/ -class DecoupledIO[+T <: Data](gen: T) extends Bundle +/** An I/O Bundle containing 'valid' and 'ready' signals that handshake + * the transfer of data stored in the 'bits' subfield. + * The base protocol implied by the directionality is that the consumer + * uses the flipped interface. Actual semantics of ready/valid are + * enforced via use of concrete subclasses. + */ +abstract class ReadyValidIO[+T <: Data](gen: T) extends Bundle { val ready = Input(Bool()) val valid = Output(Bool()) val bits = Output(gen.chiselCloneType) - override def cloneType: this.type = DecoupledIO(gen).asInstanceOf[this.type] } object DecoupledIO { @@ -23,6 +27,19 @@ object DecoupledIO { */ def apply[T <: Data](gen: T): DecoupledIO[T] = new DecoupledIO(gen) + /** Take an IrrevocableIO and cast it to a DecoupledIO. + * This cast is only safe to do in cases where the IrrevocableIO + * is being produced as an output. + */ + def apply[T <: Data](irr: IrrevocableIO[T]): DecoupledIO[T] = { + require(getFirrtlDirection(irr.bits) == OUTPUT, "Only safe to cast produced Irrevocable bits to Decoupled.") + val d = Wire(new DecoupledIO(irr.bits)) + d.bits := irr.bits + d.valid := irr.valid + irr.ready := d.ready + d + } + implicit class AddMethodsToDecoupled[T<:Data](val target: DecoupledIO[T]) extends AnyVal { def fire(): Bool = target.ready && target.valid @@ -65,6 +82,33 @@ object DecoupledIO { // } } +/** A concrete subclass of ReadyValidIO signalling that the user expects a + * "decoupled" interface: 'valid' indicates that the producer has + * put valid data in 'bits', and 'ready' indicates that the consumer is ready + * to accept the data this cycle. No requirements are placed on the signalling + * of ready or valid. + */ +class DecoupledIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen) +{ + override def cloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type] +} + +/** A concrete subclass of ReadyValidIO that promises to not change + * the value of 'bits' after a cycle where 'valid' is high and 'ready' is low. + * Additionally, once 'valid' is raised it will never be lowered until after + * 'ready' has also been raised. + */ +class IrrevocableIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen) +{ + override def cloneType: this.type = new IrrevocableIO(gen).asInstanceOf[this.type] +} + +/** Factory adds an irrevocable handshaking protocol to a data bundle. */ +object Irrevocable +{ + def apply[T <: Data](gen: T): IrrevocableIO[T] = new IrrevocableIO(gen) +} + object EnqIO { def apply[T<:Data](gen: T): DecoupledIO[T] = DecoupledIO(gen) } @@ -98,7 +142,8 @@ class QueueIO[T <: Data](gen: T, entries: Int) extends Bundle * q.io.enq <> producer.io.out * consumer.io.in <> q.io.deq }}} */ -class Queue[T <: Data](gen: T, val entries: Int, +class Queue[T <: Data](gen: T, + val entries: Int, pipe: Boolean = false, flow: Boolean = false, override_reset: Option[Bool] = None) @@ -159,22 +204,43 @@ extends Module(override_reset=override_reset) { } } -/** Generic hardware queue. Required parameter entries controls - the depth of the queues. The width of the queue is determined - from the inputs. - - Example usage: - {{{ val q = Queue(DecoupledIO(UInt()), 16) - q.io.enq <> producer.io.out - consumer.io.in <> q.io.deq }}} +/** Factory for a generic hardware queue. Required parameter 'entries' controls + * the depth of the queues. The width of the queue is determined + * from the input 'enq'. + * + * Example usage: + * {{{ consumer.io.in <> Queue(producer.io.out, 16) }}} */ object Queue { - def apply[T <: Data](enq: DecoupledIO[T], entries: Int = 2, pipe: Boolean = false): DecoupledIO[T] = { - val q = Module(new Queue(enq.bits.chiselCloneType, entries, pipe)) + /** Create a queue and supply a DecoupledIO containing the product. */ + def apply[T <: Data]( + enq: ReadyValidIO[T], + entries: Int = 2, + pipe: Boolean = false, + flow: Boolean = false): DecoupledIO[T] = { + val q = Module(new Queue(enq.bits.cloneType, entries, pipe, flow)) q.io.enq.valid := enq.valid // not using <> so that override is allowed q.io.enq.bits := enq.bits enq.ready := q.io.enq.ready TransitName(q.io.deq, q) } + + /** Create a queue and supply a IrrevocableIO containing the product. + * Casting from Decoupled is safe here because we know the Queue has + * Irrevocable semantics; we didn't want to change the return type of + * apply() for backwards compatibility reasons. + */ + def irrevocable[T <: Data]( + enq: ReadyValidIO[T], + entries: Int = 2, + pipe: Boolean = false, + flow: Boolean = false): IrrevocableIO[T] = { + val deq = apply(enq, entries, pipe, flow) + val irr = Wire(new IrrevocableIO(deq.bits)) + irr.bits := deq.bits + irr.valid := deq.valid + deq.ready := irr.ready + irr + } } |
