.. _cdes: Context-Dependent-Environments ======================================== Readers may notice that the parameterization system frequently uses ``(site, here, up)``. This construct is an artifact of the "context-dependent-environment" system which Chipyard and Rocket Chip both leverage for powerful composable hardware configuration. The CDE parameterization system provides different "Views" of a single global parameterization. The syntax for accessing a ``Field`` within a ``View`` is ``my_view(MyKey, site_view)``, where ``site_view`` is a "global" view that will be passed recursively into various functions and key-lookups in the call-stack of ``my_view(MyKey, site_view)``. .. note:: Rocket Chip based designs will frequently use ``val p: Parameters`` and ``p(SomeKey)`` to lookup the value of a key. ``Parameters`` is just a subclass of the ``View`` abstract class, and ``p(SomeKey)`` really expands into ``p(SomeKey, p)``. This is because we consider the call ``p(SomeKey)`` to be the "site", or "source" of the original key query, so we need to pass in the view of the configuration provided by ``p`` recursively to future calls through the ``site`` argument. Consider the following example using CDEs. .. code:: scala case object SomeKeyX extends Field[Boolean](false) // default is false case object SomeKeyY extends Field[Boolean](false) // default is false case object SomeKeyZ extends Field[Boolean](false) // default is false class WithX(b: Boolean) extends Config((site, here, up) => { case SomeKeyX => b }) class WithY(b: Boolean) extends Config((site, here, up) => { case SomeKeyY => b }) When forming a query based on a ``Parameters`` object, like ``p(SomeKeyX)``, the configuration system traverses the "chain" of config fragments until it finds a partial function which is defined at the key, and then returns that value. .. code:: scala val params = new Config(new WithX(true) ++ new WithY(true)) // "chain" together config fragments params(SomeKeyX) // evaluates to true params(SomeKeyY) // evaluates to true params(SomeKeyZ) // evaluates to false In this example, the evaluation of ``params(SomeKeyX)`` will terminate in the partial function defined in ``WithX(true)``, while the evaluation of ``params(SomeKeyY)`` will terminate in the partial function defined in ``WithY(true)``. Note that when no partial functions match, the evaluation will return the default value for that parameter. Config fragments take precedence from left to right, meaning that a fragment at the start of the chain can override the value of a fragment to the right. It helps to read the fragment chain from right to left. .. code:: scala case object SomeKeyX extends Field[Int](0) class WithX(n: Int) extends Config((site, here, up) => { case SomeKeyX => n }) val params = new Config(new WithX(10) ++ new WithX(5)) println(params(SomeKeyX)) // evaluates to 10 The real power of CDEs arises from the ``(site, here, up)`` parameters to the partial functions, which provide useful "views" into the global parameterization that the partial functions may access to determine a parameterization. .. note:: Additional information on the motivations for CDEs can be found in Chapter 2 of `Henry Cook's Thesis `_ . Site ~~~~ ``site`` provides a ``View`` of the "source" of the original parameter query. .. code:: scala class WithXEqualsYSite extends Config((site, here, up) => { case SomeKeyX => site(SomeKeyY) // expands to site(SomeKeyY, site) }) val params_1 = new Config(new WithXEqualsYSite ++ new WithY(true)) val params_2 = new Config(new WithY(true) ++ new WithXEqualsYSite) params_1(SomeKeyX) // evaluates to true params_2(SomeKeyX) // evaluates to true In this example, the partial function in ``WithXEqualsYSite`` will look up the value of ``SomeKeyY`` in the original ``params_N`` object, which becomes ``site`` in each call in the recursive traversal. Here ~~~~ ``here`` provides a ``View`` of the locally defined config, which typically just contains some partial function. .. code:: scala class WithXEqualsYHere extends Config((site, here, up) => { case SomeKeyY => false case SomeKeyX => here(SomeKeyY, site) }) val params_1 = new Config(new WithXEqualsYHere ++ new WithY(true)) val params_2 = new Config(new WithY(true) ++ new WithXEqualsYHere) params_1(SomeKeyX) // evaluates to false params_2(SomeKeyX) // evaluates to false In this example, note that although our final parameterization in ``params_2`` has ``SomeKeyY`` set to ``true``, the call to ``here(SomeKeyY, site)`` only looks in the local partial function defined in ``WithXEqualsYHere``. Note that we pass ``site`` to ``here`` since ``site`` may be used in the recursive call. Up ~~~~ ``up`` provides a ``View`` of the previously defined set of partial functions in the "chain" of partial functions. This is useful when we want to lookup a previously set value for some key, but not the final value for that key. .. code:: scala class WithXEqualsYUp extends Config((site, here, up) => { case SomeKeyX => up(SomeKeyY, site) }) val params_1 = new Config(new WithXEqualsYUp ++ new WithY(true)) val params_2 = new Config(new WithY(true) ++ new WithXEqualsYUp) params_1(SomeKeyX) // evaluates to true params_2(SomeKeyX) // evaluates to false In this example, note how ``up(SomeKeyY, site)`` in ``WithXEqualsYUp`` will refer to *either* the the partial function defining ``SomeKeyY`` in ``WithY(true)`` *or* the default value for ``SomeKeyY`` provided in the original ``case object SomeKeyY`` definition, *depending on the order in which the config fragments were used*. Since the order of config fragments affects the the order of the ``View`` traversal, ``up`` provides a different ``View`` of the parameterization in ``params_1`` and ``params_2``. Also note that again, ``site`` must be recursively passed through the call to ``up``.