Add documentation on HarnessBinders
This commit is contained in:
@@ -12,11 +12,14 @@ to verify functionality.
|
|||||||
Setting up Dromajo Co-simulation
|
Setting up Dromajo Co-simulation
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
Dromajo co-simulation is setup to work when two config fragments are added to a BOOM config.
|
Dromajo co-simulation is setup to work when three config fragments are added to a BOOM config.
|
||||||
First, a ``chipyard.config.WithTraceIO`` config fragment must be added so that BOOM's traceport is enabled.
|
|
||||||
Second, a ``chipyard.iobinders.WithSimDromajoBridge`` config fragment must be added to
|
* A ``chipyard.config.WithTraceIO`` config fragment must be added so that BOOM's traceport is enabled.
|
||||||
connect the Dromajo co-simulator to the traceport.
|
* A ``chipyard.iobinders.WithTraceIOPunchthrough`` config fragment must be added to add the ``TraceIO`` to the ``ChipTop``
|
||||||
Once both config fragments are added Dromajo should be enabled.
|
* A ``chipyard.harness.WithSimDromajoBridge`` config fragment must be added to instantiate a Dromajo cosimulator in the ``TestHarness`` and connect it to the ``ChipTop``'s ``TraceIO``
|
||||||
|
|
||||||
|
|
||||||
|
Once all config fragments are added Dromajo should be enabled.
|
||||||
|
|
||||||
To build/run Dromajo with a BOOM design, run your configuration the following make commands:
|
To build/run Dromajo with a BOOM design, run your configuration the following make commands:
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ ChipTop/DUT
|
|||||||
``ChipTop`` is the top-level module that instantiates the ``System`` submodule, usually an instance of the concrete class ``DigitalTop``.
|
``ChipTop`` is the top-level module that instantiates the ``System`` submodule, usually an instance of the concrete class ``DigitalTop``.
|
||||||
The vast majority of the design resides in the ``System``.
|
The vast majority of the design resides in the ``System``.
|
||||||
Other components that exist inside the ``ChipTop`` layer are generally IO cells, clock receivers and multiplexers, reset synchronizers, and other analog IP that needs to exist outside of the ``System``.
|
Other components that exist inside the ``ChipTop`` layer are generally IO cells, clock receivers and multiplexers, reset synchronizers, and other analog IP that needs to exist outside of the ``System``.
|
||||||
The ``IOBinders`` are responsible for instantiating the IO cells and defining the test harness collateral that connects to the top-level ports.
|
The ``IOBinders`` are responsible for instantiating the IO cells for ``ChipTop`` IO that correspond to IO of the ``System``.
|
||||||
Most of these types of devices can be instantiated using custom ``IOBinders``, so the provided ``ChipTop`` and ``ChipTopCaughtReset`` classes are sufficient.
|
The ``HarnessBinders`` are responsible for instantiating test harness collateral that connects to the ``ChipTop`` ports.
|
||||||
However, if needed, the ``BaseChipTop`` abstract class can be extended for building more custom ``ChipTop`` designs.
|
Most types of devices and testing collateral can be instantiated using custom ``IOBinders`` and ``HarnessBinders``.
|
||||||
|
|
||||||
|
|
||||||
System/DigitalTop
|
System/DigitalTop
|
||||||
|
|||||||
@@ -1,41 +1,45 @@
|
|||||||
|
IOBinders and HarnessBinders
|
||||||
|
============================
|
||||||
|
|
||||||
|
In Chipyard we use special ``Parameters`` keys, ``IOBinders`` and ``HarnessBinders`` to bridge the gap between digital system IOs and TestHarness collateral.
|
||||||
|
|
||||||
IOBinders
|
IOBinders
|
||||||
=========
|
=========
|
||||||
|
|
||||||
In Chipyard we use a special ``Parameters`` key, ``IOBinders`` to instantiate IO cells in the ``ChipTop`` layer and determine what modules to bind to the IOs of a ``ChipTop`` in the ``TestHarness``.
|
The ``IOBinder`` functions are responsible for instantiating IO cells and IOPorts in the ``ChipTop`` layer.
|
||||||
|
|
||||||
|
``IOBinders`` are typically defined using the ``OverrideIOBinder`` or ``ComposeIOBinder`` macros. An ``IOBInder`` consists of a function matching ``Systems`` with a given trait that generates IO ports and IOCells, and returns a list of generated ports and cells.
|
||||||
|
|
||||||
|
For example, the ``WithUARTIOCells`` IOBinder specifies will, for any ``System`` that might have UART ports (``HasPeripheryUARTModuleIMP``, generate ports within the ``ChipTop`` (``ports``) as well as IOCells with the appropriate type and direction (``cells2d``). This function returns a the list of generated ports, and the list of generate IOCells. The list of generated ports is passed to the ``HarnessBinders`` such that they can be connected to ``TestHarness`` devices.
|
||||||
|
|
||||||
|
|
||||||
.. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala
|
.. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala
|
||||||
:language: scala
|
:language: scala
|
||||||
:start-after: DOC include start: IOBinders
|
:start-after: DOC include start: WithUARTIOCells
|
||||||
:end-before: DOC include end: IOBinders
|
:end-before: DOC include end: WithUARTIOCells
|
||||||
|
|
||||||
|
HarnessBinders
|
||||||
|
==============
|
||||||
|
|
||||||
This special key solves the problem of duplicating test-harnesses for each different ``System`` type.
|
The ``HarnessBinder`` functions determine what modules to bind to the IOs of a ``ChipTop`` in the ``TestHarness``. The ``HarnessBinder`` interface is designed to be reused across various simulation modes, enabling decoupling of the target design from simulation and testing concerns.
|
||||||
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.
|
|
||||||
Each ``IOBinder`` returns a tuple of three values: the list of ``ChipTop`` ports created by the ``IOBinder``, the list of all IO cell modules instantiated by the ``IOBinder``, and an optional function to be called inside the test harness.
|
|
||||||
This function is responsible for instantiating logic inside the ``TestHarness`` to appropriately drive the ``ChipTop`` IO ports created by the ``IOBinder``.
|
|
||||||
Conveniently, because the ``IOBinder`` is generating the port, it may also use the port inside this function, which prevents the ``BaseChipTop`` code from ever needing to access the port ``val``, thus having the ``IOBinder`` house all port specific code.
|
|
||||||
This scheme prevents the need to have two separate binder functions for each ``System`` trait.
|
|
||||||
When creating custom ``IOBinders`` it is important to use ``suggestName`` to name ports; otherwise Chisel will raise an exception trying to name the IOs.
|
|
||||||
The example ``IOBinders`` demonstrate this.
|
|
||||||
|
|
||||||
As an example, the ``WithGPIOTiedOff`` IOBinder creates IO cells for the GPIO module(s) instantiated in the ``System``, then punches out new ``Analog`` ports for each one.
|
* For SW RTL simulations, the default set of ``HarnessBinders`` instantiate software-simulated models of various devices, for example external memory or UART, and connect those models to the IOs of the ``ChipTop``.
|
||||||
The test harness simply ties these off, but additional logic could be inserted to perform some kind of test in the ``TestHarness``.
|
* For FireSim simulations, FireSim-specific ``HarnessBinders`` instantiate ``Bridges``, which faciliate cycle-accurate simulation across the simulated chip's IOs. See the FireSim documentation for more details.
|
||||||
|
* In the future, a Chipyard FPGA prototyping flow may use ``HarnessBinders`` to connect ``ChipTop`` IOs to other devices or IOs in the FPGA harness.
|
||||||
|
|
||||||
.. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala
|
For FireSim simulations, the ``HarnessBinder`` attach ``Bridge`` modules (See the FireSim documentation for more details).
|
||||||
|
|
||||||
|
Like ``IOBinders``, ``HarnessBinders`` are defined using macros (``OverrideHarnessBinder, ComposeHarnessBinder``), and matches ``Systems`` with a given trait. However, ``HarnessBinders`` are also passed a reference to the ``TestHarness`` (``th: HasHarnessSignalReferences``) and the list of ports generated by the corresponding ``IOBinder`` (``ports: Seq[Data]``).
|
||||||
|
|
||||||
|
For exmaple, the ``WithUARTAdapter`` will connect the UART SW display adapter to the ports generated by the ``WithUARTIOCells`` described earlier, if those ports are present.
|
||||||
|
|
||||||
|
.. literalinclude:: ../../generators/chipyard/src/main/scala/HarnessBinders.scala
|
||||||
:language: scala
|
:language: scala
|
||||||
:start-after: DOC include start: WithGPIOTiedOff
|
:start-after: DOC include start: WithUARTAdapter
|
||||||
:end-before: DOC include end: WithGPIOTiedOff
|
:end-before: DOC include end: WithUARTAdapter
|
||||||
|
|
||||||
|
The ``IOBinder`` and ``HarnesBinder`` system is designed to enable decoupling of concerns between target design and simulation ssystem.
|
||||||
|
|
||||||
``IOBinders`` also do not need to create ports. Some ``IOBinders`` can simply insert circuitry inside the ``ChipTop`` layer.
|
For a given set of chip IOs, there may be not only multiple simulation platforms ("harnesses", so-to-speak), but also multiple simulation strategies. For example, the choice of whether to connect the backing AXI4 memory port to a accurate DRAM model (``SimDRAM``) or a simple simulated memory model (``SimAXIMem``) is isolated in ``HarnessBinders``, and does not affect target RTL generation.
|
||||||
For example, the ``WithSimAXIMemTiedOff`` IOBinder specifies that any ``System`` which matches ``CanHaveMasterAXI4MemPortModuleImp`` will have a ``SimAXIMem`` connected inside ``ChipTop``.
|
|
||||||
|
|
||||||
.. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala
|
Similarly, for a given simulation platform and strategy, there may be multiple strategies for generating the chip IOs. This target-design configuration is isolated in the ``IOBinders``.
|
||||||
:language: scala
|
|
||||||
:start-after: DOC include start: WithSimAXIMem
|
|
||||||
:end-before: DOC include end: WithSimAXIMem
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|||||||
@@ -66,12 +66,14 @@ class WithGPIOTiedOff extends OverrideHarnessBinder({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// DOC include start: WithUARTAdapter
|
||||||
class WithUARTAdapter extends OverrideHarnessBinder({
|
class WithUARTAdapter extends OverrideHarnessBinder({
|
||||||
(system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
|
(system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
|
||||||
UARTAdapter.connect(ports.map(_.asInstanceOf[UARTPortIO]))(system.p)
|
UARTAdapter.connect(ports.map(_.asInstanceOf[UARTPortIO]))(system.p)
|
||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
// DOC include end: WithUARTAdapter
|
||||||
|
|
||||||
class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({
|
class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({
|
||||||
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
|
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
|
||||||
|
|||||||
@@ -40,13 +40,6 @@ import scala.reflect.{ClassTag}
|
|||||||
|
|
||||||
// You can add your own binder by adding a new (key, fn) pair, typically by using
|
// You can add your own binder by adding a new (key, fn) pair, typically by using
|
||||||
// the OverrideIOBinder or ComposeIOBinder macros
|
// the OverrideIOBinder or ComposeIOBinder macros
|
||||||
|
|
||||||
|
|
||||||
// DOC include start: IOBinders
|
|
||||||
// This type describes a function callable on the TestHarness instance. Its return type is unused.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case object IOBinders extends Field[Map[String, (Any) => (Seq[Data], Seq[IOCell])]](
|
case object IOBinders extends Field[Map[String, (Any) => (Seq[Data], Seq[IOCell])]](
|
||||||
Map[String, (Any) => (Seq[Data], Seq[IOCell])]().withDefaultValue((Any) => (Nil, Nil))
|
Map[String, (Any) => (Seq[Data], Seq[IOCell])]().withDefaultValue((Any) => (Nil, Nil))
|
||||||
)
|
)
|
||||||
@@ -59,7 +52,6 @@ object ApplyIOBinders {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Note: The parameters instance is accessible only through LazyModule
|
// Note: The parameters instance is accessible only through LazyModule
|
||||||
// or LazyModuleImpLike. The self-type requirement in traits like
|
// or LazyModuleImpLike. The self-type requirement in traits like
|
||||||
// CanHaveMasterAXI4MemPort is insufficient to make it accessible to the IOBinder
|
// CanHaveMasterAXI4MemPort is insufficient to make it accessible to the IOBinder
|
||||||
@@ -116,8 +108,6 @@ object BoreHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DOC include end: IOBinders
|
|
||||||
|
|
||||||
|
|
||||||
case object IOCellKey extends Field[IOCellTypeParams](GenericIOCellParams())
|
case object IOCellKey extends Field[IOCellTypeParams](GenericIOCellParams())
|
||||||
|
|
||||||
@@ -140,7 +130,7 @@ class WithGPIOCells extends OverrideIOBinder({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// DOC include start: WithUARTIOCells
|
||||||
class WithUARTIOCells extends OverrideIOBinder({
|
class WithUARTIOCells extends OverrideIOBinder({
|
||||||
(system: HasPeripheryUARTModuleImp) => {
|
(system: HasPeripheryUARTModuleImp) => {
|
||||||
val (ports, cells2d) = system.uart.zipWithIndex.map({ case (u, i) =>
|
val (ports, cells2d) = system.uart.zipWithIndex.map({ case (u, i) =>
|
||||||
@@ -151,6 +141,7 @@ class WithUARTIOCells extends OverrideIOBinder({
|
|||||||
(ports, cells2d.flatten)
|
(ports, cells2d.flatten)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
// DOC include end: WithUARTIOCells
|
||||||
|
|
||||||
class WithSPIIOCells extends OverrideIOBinder({
|
class WithSPIIOCells extends OverrideIOBinder({
|
||||||
(system: HasPeripherySPIFlashModuleImp) => {
|
(system: HasPeripherySPIFlashModuleImp) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user