6.12. IOBindersΒΆ
In Chipyard we use a special Parameters
key, IOBinders
to determine what modules to bind to the IOs of a Top
in the TestHarness
.
case object IOBinders extends Field[Map[String, (Clock, Bool, Bool, Any) => Seq[Any]]](
Map[String, (Clock, Bool, Bool, Any) => Seq[Any]]().withDefaultValue((c: Clock, r: Bool, s: Bool, t: Any) => Nil)
)
// This macro overrides previous matches on some Top mixin. This is useful for
// binders which drive IO, since those typically cannot be composed
class OverrideIOBinder[T](fn: => (Clock, Bool, Bool, T) => Seq[Any])(implicit tag: ClassTag[T]) extends Config((site, here, up) => {
case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString ->
((clock: Clock, reset: Bool, success: Bool, t: Any) => {
t match {
case top: T => fn(clock, reset, success, top)
case _ => Nil
}
})
)
})
// This macro composes with previous matches on some Top mixin. This is useful for
// annotation-like binders, since those can typically be composed
class ComposeIOBinder[T](fn: => (Clock, Bool, Bool, T) => Seq[Any])(implicit tag: ClassTag[T]) extends Config((site, here, up) => {
case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString ->
((clock: Clock, reset: Bool, success: Bool, t: Any) => {
t match {
case top: T => (up(IOBinders, site)(tag.runtimeClass.toString)(clock, reset, success, top)
++ fn(clock, reset, success, top))
case _ => Nil
}
})
)
})
This special key solves the problem of duplicating test-harnesses for each different Top
type.
You could just as well create a custom harness module that attaches IOs explicitly. Instead, the IOBinders key provides a map from Scala traits to attachment behaviors.
For example, the WithSimAXIMemTiedOff
IOBinder specifies that any Top
which matches CanHaveMasterAXI4MemPortModuleImp
will have a SimAXIMem
connected.
class WithSimAXIMem extends OverrideIOBinder({
(c, r, s, top: CanHaveMasterAXI4MemPortModuleImp) => top.connectSimAXIMem(); Nil
})
These classes are all Config
objects, which can be mixed into the configs to specify IO connection behaviors.
There are two macros for generating these Config``s. ``OverrideIOBinder
overrides any existing behaviors set for a particular IO in the Config
object. This macro is frequently used because typically top-level IOs drive or are driven by only one source, so a composition of IOBinders
does not make sense. The ComposeIOBinder
macro provides the functionality of not overriding existing behaviors.