Skip to content

Commit e45609e

Browse files
authored
[nfc] Break Pipe code out of Valid.scala (#4588)
Move code related to the `Pipe` utility into its own file. Previously, this code lived inside Valid.scala which would make it harder to locate. Signed-off-by: Schuyler Eldridge <[email protected]>
1 parent 3da79ae commit e45609e

File tree

2 files changed

+129
-122
lines changed

2 files changed

+129
-122
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package chisel3.util
4+
5+
import chisel3._
6+
import chisel3.experimental.prefix
7+
import chisel3.util.simpleClassName
8+
9+
/** A factory to generate a hardware pipe. This can be used to delay [[Valid]] data by a design-time configurable number
10+
* of cycles.
11+
*
12+
* Here, we construct three different pipes using the different provided `apply` methods and hook them up together. The
13+
* types are explicitly specified to show that these all communicate using [[Valid]] interfaces:
14+
* {{{
15+
* val in: Valid[UInt] = Wire(Valid(UInt(2.W)))
16+
*
17+
* /* A zero latency (combinational) pipe is connected to 'in' */
18+
* val foo: Valid[UInt] = Pipe(in.valid, in.bits, 0)
19+
*
20+
* /* A one-cycle pipe is connected to the output of 'foo' */
21+
* val bar: Valid[UInt] = Pipe(foo.valid, foo.bits)
22+
*
23+
* /* A two-cycle pipe is connected to the output of 'bar' */
24+
* val baz: Valid[UInt] = Pipe(bar, 2)
25+
* }}}
26+
*
27+
* @see [[Pipe Pipe class]] for an alternative API
28+
* @see [[Valid]] interface
29+
* @see [[Queue]] and the [[Queue$ Queue factory]] for actual queues
30+
* @see The [[ShiftRegister$ ShiftRegister factory]] to generate a pipe without a [[Valid]] interface
31+
* @define returnType the [[Valid]] output of the final pipeline stage
32+
*/
33+
object Pipe {
34+
35+
/** Generate a pipe from an explicit valid bit and some data
36+
* @param enqValid the valid bit (must be a hardware type)
37+
* @param enqBits the data (must be a hardware type)
38+
* @param latency the number of pipeline stages
39+
* @return $returnType
40+
*/
41+
def apply[T <: Data](enqValid: Bool, enqBits: T, latency: Int): Valid[T] = {
42+
require(latency >= 0, "Pipe latency must be greater than or equal to zero!")
43+
if (latency == 0) {
44+
val out = Wire(Valid(chiselTypeOf(enqBits)))
45+
out.valid := enqValid
46+
out.bits := enqBits
47+
out
48+
} else
49+
prefix("pipe") {
50+
val v = RegNext(enqValid, false.B)
51+
val b = RegEnable(enqBits, enqValid)
52+
apply(v, b, latency - 1)
53+
}
54+
}
55+
56+
/** Generate a one-stage pipe from an explicit valid bit and some data
57+
* @param enqValid the valid bit (must be a hardware type)
58+
* @param enqBits the data (must be a hardware type)
59+
* @return $returnType
60+
*/
61+
def apply[T <: Data](enqValid: Bool, enqBits: T): Valid[T] = {
62+
apply(enqValid, enqBits, 1)
63+
}
64+
65+
/** Generate a pipe for a [[Valid]] interface
66+
* @param enq a [[Valid]] interface (must be a hardware type)
67+
* @param latency the number of pipeline stages
68+
* @return $returnType
69+
*/
70+
def apply[T <: Data](enq: Valid[T], latency: Int = 1): Valid[T] = {
71+
apply(enq.valid, enq.bits, latency)
72+
}
73+
}
74+
75+
/** Pipeline module generator parameterized by data type and latency.
76+
*
77+
* This defines a module with one input, `enq`, and one output, `deq`. The input and output are [[Valid]] interfaces
78+
* that wrap some Chisel type, e.g., a [[UInt]] or a [[Bundle]]. This generator will then chain together a number of
79+
* pipeline stages that all advance when the input [[Valid]] `enq` fires. The output `deq` [[Valid]] will fire only
80+
* when valid data has made it all the way through the pipeline.
81+
*
82+
* As an example, to construct a 4-stage pipe of 8-bit [[UInt]]s and connect it to a producer and consumer, you can use
83+
* the following:
84+
* {{{
85+
* val foo = Module(new Pipe(UInt(8.W)), 4)
86+
* pipe.io.enq := producer.io
87+
* consumer.io := pipe.io.deq
88+
* }}}
89+
*
90+
* If you already have the [[Valid]] input or the components of a [[Valid]] interface, it may be simpler to use the
91+
* [[Pipe$ Pipe factory]] companion object. This, which [[Pipe]] internally utilizes, will automatically connect the
92+
* input for you.
93+
*
94+
* @param gen a Chisel type
95+
* @param latency the number of pipeline stages
96+
* @see [[Pipe$ Pipe factory]] for an alternative API
97+
* @see [[Valid]] interface
98+
* @see [[Queue]] and the [[Queue$ Queue factory]] for actual queues
99+
* @see The [[ShiftRegister$ ShiftRegister factory]] to generate a pipe without a [[Valid]] interface
100+
*/
101+
class Pipe[T <: Data](val gen: T, val latency: Int = 1) extends Module {
102+
103+
/** A non-ambiguous name of this `Pipe` for use in generated Verilog names.
104+
* Includes the latency cycle count in the name as well as the parameterized
105+
* generator's `typeName`, e.g. `Pipe4_UInt4`
106+
*/
107+
override def desiredName = s"${simpleClassName(this.getClass)}${latency}_${gen.typeName}"
108+
109+
/** Interface for [[Pipe]]s composed of a [[Valid]] input and [[Valid]] output
110+
* @define notAQueue
111+
* @groupdesc Signals Hardware fields of the Bundle
112+
*/
113+
class PipeIO extends Bundle {
114+
115+
/** [[Valid]] input
116+
* @group Signals
117+
*/
118+
val enq = Input(Valid(gen))
119+
120+
/** [[Valid]] output. Data will appear here `latency` cycles after being valid at `enq`.
121+
* @group Signals
122+
*/
123+
val deq = Output(Valid(gen))
124+
}
125+
126+
val io = IO(new PipeIO)
127+
128+
io.deq <> Pipe(io.enq, latency)
129+
}

src/main/scala/chisel3/util/Valid.scala

Lines changed: 0 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -96,125 +96,3 @@ object Valid {
9696
*/
9797
def apply[T <: Data](gen: T): Valid[T] = new Valid(gen)
9898
}
99-
100-
/** A factory to generate a hardware pipe. This can be used to delay [[Valid]] data by a design-time configurable number
101-
* of cycles.
102-
*
103-
* Here, we construct three different pipes using the different provided `apply` methods and hook them up together. The
104-
* types are explicitly specified to show that these all communicate using [[Valid]] interfaces:
105-
* {{{
106-
* val in: Valid[UInt] = Wire(Valid(UInt(2.W)))
107-
*
108-
* /* A zero latency (combinational) pipe is connected to 'in' */
109-
* val foo: Valid[UInt] = Pipe(in.valid, in.bits, 0)
110-
*
111-
* /* A one-cycle pipe is connected to the output of 'foo' */
112-
* val bar: Valid[UInt] = Pipe(foo.valid, foo.bits)
113-
*
114-
* /* A two-cycle pipe is connected to the output of 'bar' */
115-
* val baz: Valid[UInt] = Pipe(bar, 2)
116-
* }}}
117-
*
118-
* @see [[Pipe Pipe class]] for an alternative API
119-
* @see [[Valid]] interface
120-
* @see [[Queue]] and the [[Queue$ Queue factory]] for actual queues
121-
* @see The [[ShiftRegister$ ShiftRegister factory]] to generate a pipe without a [[Valid]] interface
122-
* @define returnType the [[Valid]] output of the final pipeline stage
123-
*/
124-
object Pipe {
125-
126-
/** Generate a pipe from an explicit valid bit and some data
127-
* @param enqValid the valid bit (must be a hardware type)
128-
* @param enqBits the data (must be a hardware type)
129-
* @param latency the number of pipeline stages
130-
* @return $returnType
131-
*/
132-
def apply[T <: Data](enqValid: Bool, enqBits: T, latency: Int): Valid[T] = {
133-
require(latency >= 0, "Pipe latency must be greater than or equal to zero!")
134-
if (latency == 0) {
135-
val out = Wire(Valid(chiselTypeOf(enqBits)))
136-
out.valid := enqValid
137-
out.bits := enqBits
138-
out
139-
} else
140-
prefix("pipe") {
141-
val v = RegNext(enqValid, false.B)
142-
val b = RegEnable(enqBits, enqValid)
143-
apply(v, b, latency - 1)
144-
}
145-
}
146-
147-
/** Generate a one-stage pipe from an explicit valid bit and some data
148-
* @param enqValid the valid bit (must be a hardware type)
149-
* @param enqBits the data (must be a hardware type)
150-
* @return $returnType
151-
*/
152-
def apply[T <: Data](enqValid: Bool, enqBits: T): Valid[T] = {
153-
apply(enqValid, enqBits, 1)
154-
}
155-
156-
/** Generate a pipe for a [[Valid]] interface
157-
* @param enq a [[Valid]] interface (must be a hardware type)
158-
* @param latency the number of pipeline stages
159-
* @return $returnType
160-
*/
161-
def apply[T <: Data](enq: Valid[T], latency: Int = 1): Valid[T] = {
162-
apply(enq.valid, enq.bits, latency)
163-
}
164-
}
165-
166-
/** Pipeline module generator parameterized by data type and latency.
167-
*
168-
* This defines a module with one input, `enq`, and one output, `deq`. The input and output are [[Valid]] interfaces
169-
* that wrap some Chisel type, e.g., a [[UInt]] or a [[Bundle]]. This generator will then chain together a number of
170-
* pipeline stages that all advance when the input [[Valid]] `enq` fires. The output `deq` [[Valid]] will fire only
171-
* when valid data has made it all the way through the pipeline.
172-
*
173-
* As an example, to construct a 4-stage pipe of 8-bit [[UInt]]s and connect it to a producer and consumer, you can use
174-
* the following:
175-
* {{{
176-
* val foo = Module(new Pipe(UInt(8.W)), 4)
177-
* pipe.io.enq := producer.io
178-
* consumer.io := pipe.io.deq
179-
* }}}
180-
*
181-
* If you already have the [[Valid]] input or the components of a [[Valid]] interface, it may be simpler to use the
182-
* [[Pipe$ Pipe factory]] companion object. This, which [[Pipe]] internally utilizes, will automatically connect the
183-
* input for you.
184-
*
185-
* @param gen a Chisel type
186-
* @param latency the number of pipeline stages
187-
* @see [[Pipe$ Pipe factory]] for an alternative API
188-
* @see [[Valid]] interface
189-
* @see [[Queue]] and the [[Queue$ Queue factory]] for actual queues
190-
* @see The [[ShiftRegister$ ShiftRegister factory]] to generate a pipe without a [[Valid]] interface
191-
*/
192-
class Pipe[T <: Data](val gen: T, val latency: Int = 1) extends Module {
193-
194-
/** A non-ambiguous name of this `Pipe` for use in generated Verilog names.
195-
* Includes the latency cycle count in the name as well as the parameterized
196-
* generator's `typeName`, e.g. `Pipe4_UInt4`
197-
*/
198-
override def desiredName = s"${simpleClassName(this.getClass)}${latency}_${gen.typeName}"
199-
200-
/** Interface for [[Pipe]]s composed of a [[Valid]] input and [[Valid]] output
201-
* @define notAQueue
202-
* @groupdesc Signals Hardware fields of the Bundle
203-
*/
204-
class PipeIO extends Bundle {
205-
206-
/** [[Valid]] input
207-
* @group Signals
208-
*/
209-
val enq = Input(Valid(gen))
210-
211-
/** [[Valid]] output. Data will appear here `latency` cycles after being valid at `enq`.
212-
* @group Signals
213-
*/
214-
val deq = Output(Valid(gen))
215-
}
216-
217-
val io = IO(new PipeIO)
218-
219-
io.deq <> Pipe(io.enq, latency)
220-
}

0 commit comments

Comments
 (0)