Skip to content

Commit d59874a

Browse files
seldridgejackkoenig
andcommitted
[core] Add BlockReturnHandler type class
Add a type class that can be used to do special handling of values returned from layer blocks. This effectively causes values of type `Data` to become a wire of layer-colored probe type driven by the value returned. For any other type, this will return `Unit`. This will be used in a later commit to change the behavior of layer blocks to work in the above way. Co-authored-by: Jack Koenig <[email protected]> Signed-off-by: Schuyler Eldridge <[email protected]>
1 parent a018a54 commit d59874a

File tree

1 file changed

+108
-1
lines changed

1 file changed

+108
-1
lines changed

core/src/main/scala/chisel3/Layer.scala

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
package chisel3
44

5-
import chisel3.experimental.{SourceInfo, UnlocatableSourceInfo}
5+
import chisel3.Data.ProbeInfo
6+
import chisel3.experimental.{requireIsHardware, SourceInfo, UnlocatableSourceInfo}
67
import chisel3.internal.{Builder, HasId}
78
import chisel3.internal.firrtl.ir.{LayerBlock, Node}
9+
import chisel3.reflect.DataMirror
810
import chisel3.util.simpleClassName
911
import java.nio.file.{Path, Paths}
1012
import scala.annotation.tailrec
@@ -196,6 +198,111 @@ object layer {
196198
}
197199
}
198200

201+
/** A type class that describes how to post-process the return value from a layer block. */
202+
sealed trait BlockReturnHandler[A] {
203+
204+
/** The type that will be returned by this handler. */
205+
type R
206+
207+
/** Do not post-process the return value. This is what should happen if the
208+
* code early exits, i.e., if no layer block is created.
209+
*/
210+
private[chisel3] def identity(result: A): R
211+
212+
/** Post-process the return value.
213+
*
214+
* @param placeholder the location above the layer block where commands can be inserted
215+
* @param layerBlock the current layer block
216+
* @param result the return value of the layer block
217+
* @param sourceInfo source locator information
218+
* @return the post-processed result
219+
*/
220+
private[chisel3] def apply(placeholder: Placeholder, layerBlock: LayerBlock, result: A)(
221+
implicit sourceInfo: SourceInfo
222+
): R
223+
}
224+
225+
object BlockReturnHandler {
226+
227+
type Aux[A, B] = BlockReturnHandler[A] { type R = B }
228+
229+
/** Return a [[BlockReturnHandler]] that will always return [[Unit]]. */
230+
def unit[A]: Aux[A, Unit] = new BlockReturnHandler[A] {
231+
232+
override type R = Unit
233+
234+
override private[chisel3] def identity(result: A): R = ()
235+
236+
override private[chisel3] def apply(
237+
placeholder: Placeholder,
238+
layerBlock: LayerBlock,
239+
result: A
240+
)(
241+
implicit sourceInfo: SourceInfo
242+
): R = {
243+
()
244+
}
245+
246+
}
247+
248+
/** Return a [[BlockReturnHandler]] that, if a layer block is created, will
249+
* create a [[Wire]] of layer-colored probe type _above_ the layer block
250+
* and [[probe.define]] this at the end of the layer block. If no
251+
* layer-block is created, then the result is pass-through.
252+
*/
253+
implicit def layerColoredWire[A <: Data]: Aux[A, A] = new BlockReturnHandler[A] {
254+
255+
override type R = A
256+
257+
override private[chisel3] def identity(result: A): R = result
258+
259+
override private[chisel3] def apply(
260+
placeholder: Placeholder,
261+
layerBlock: LayerBlock,
262+
result: A
263+
)(
264+
implicit sourceInfo: SourceInfo
265+
): R = {
266+
// Don't allow returning non-hardware types. This avoids problems like
267+
// returning a probe type which we can't handle.
268+
requireIsHardware(result)
269+
270+
// The result wire is either a new layer-colored probe wire or an
271+
// existing layer-colored probe wire forwarded up. If it is the former,
272+
// the wire is colored with the current layer. For the latter, the wire
273+
// needs to have a compatible color. If it has one, use it. If it
274+
// needs a color, set it on the wire.
275+
val layerColoredWire = placeholder.append {
276+
result.probeInfo match {
277+
case None => Wire(probe.Probe(chiselTypeOf(result), layerBlock.layer))
278+
case Some(ProbeInfo(_, None)) => Wire(probe.Probe(result.cloneType, layerBlock.layer))
279+
case Some(ProbeInfo(_, Some(color))) =>
280+
if (!layerBlock.layer.canWriteTo(color))
281+
Builder.error(
282+
s"cannot return probe of color '${color.fullName}' from a layer block associated with layer '${layerBlock.layer.fullName}'"
283+
)
284+
Wire(chiselTypeOf(result))
285+
}
286+
}
287+
288+
// Similarly, if the result is a probe, then we forward it directly. If
289+
// it is a non-probe, then we need to probe it first.
290+
Builder.forcedUserModule.withRegion(layerBlock.region) {
291+
val source = DataMirror.hasProbeTypeModifier(result) match {
292+
case true => result
293+
case false => probe.ProbeValue(result)
294+
}
295+
probe.define(layerColoredWire, source)
296+
}
297+
298+
// Return the layer-colored wire _above_ the layer block.
299+
layerColoredWire
300+
}
301+
302+
}
303+
304+
}
305+
199306
/** Create a new layer block. This is hardware that will be enabled
200307
* collectively when the layer is enabled.
201308
*

0 commit comments

Comments
 (0)