Custom Core Integration Doc, 1st Revision
This commit is contained in:
@@ -7,34 +7,32 @@ You may want to add a custom RISC-V core to Chipyard generator. If the top modul
|
|||||||
you will first need to create a Verilog blackbox for it. See :ref:`incorporating-verilog-blocks` for instructions.
|
you will first need to create a Verilog blackbox for it. See :ref:`incorporating-verilog-blocks` for instructions.
|
||||||
Once you have a top module in Chisel, you are ready to create integrate it with Chipyard.
|
Once you have a top module in Chisel, you are ready to create integrate it with Chipyard.
|
||||||
|
|
||||||
|
``generators/ariane/src/main/scala/ArianeTile.scala`` and ``generators/boom/src/main/scala/common/tile.scala``
|
||||||
|
provide two examples of how to integrate a core.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
RoCC is not supported by custom core currently. Please use Rocket or Boom if you need to use RoCC.
|
RoCC is not supported by custom core currently. Please use Rocket or Boom as the RoCC base core if you need to use RoCC.
|
||||||
|
|
||||||
Parameter Case Classes
|
Parameter Case Classes
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Chipyard will generate a core for every ``TileParams`` object it discovered in the current config.
|
Chipyard will generate a core for every ``InstantiableTileParams`` object it discovered in the current config.
|
||||||
``TileParams`` is a trait containing the information needed to create a tile, and every custom core must implement
|
This object is derived from``TileParams``, a trait containing the information needed to create a tile. All cores must have
|
||||||
their own version of ``TileParams``, as well as ``CoreParams`` which is passed as a field in ``TileParams``.
|
their own implementation of ``InstantiableTileParams``, as well as ``CoreParams`` which is passed as a field in ``TileParams``.
|
||||||
|
|
||||||
``TileParams`` holds the parameters that are the same for every generated core, while ``CoreParams`` contains those
|
``TileParams`` holds the parameters for the tile, which are the same for every generated core, while ``CoreParams``
|
||||||
that can vary from cores to cores. They must be implemented as case classes with fields that can be overridden by
|
contains the parameters for individual cores. They must be implemented as case classes with fields that can be overridden by
|
||||||
other config fragments as the constructor parameters. See the appendix at the bottom of the page for a list of
|
other config fragments as the constructor parameters. See the appendix at the bottom of the page for a list of
|
||||||
variable to be implemented. You can also add custom fields to them, but standard fields should always be preferred.
|
variable to be implemented. You can also add custom fields to them, but standard fields should always be preferred.
|
||||||
|
|
||||||
Now you have your parameter classes, you will need config keys to hold them. There are two required keys:
|
``InstantiableTileParams[TileType]`` holds the constructor of ``TileType`` on top of the fields of ``TileParams``.
|
||||||
|
All custom cores will also need to implement ``instantiate()`` in their tile parameter class to return a new instance
|
||||||
|
of the tile class ``TileType``.
|
||||||
|
|
||||||
.. code-block:: scala
|
``TileParams``, ``InstantiableTileParams[TileType]`` and ``CoreParams`` contains the following fields (you may ignore
|
||||||
|
any fields marked "Rocket specific" and use their default values, although it is recommended to use them if you
|
||||||
case object MyTilesKey extends Field[Seq[MyTileParams]](Nil)
|
need a custom field with similar purposes):
|
||||||
case object MyCrossingKey extends Field[Seq[RocketCrossingParams]](List(RocketCrossingParams()))
|
|
||||||
|
|
||||||
``MyCrossingKey`` here is used to store information about the clock-crossing behavior of the core, and it is normally
|
|
||||||
set to its default values.
|
|
||||||
|
|
||||||
``TileParams`` and ``CoreParams`` contains the following fields (you may ignore any fields marked "Rocket specific" and
|
|
||||||
use their default values, although it is recommended to use them if you need a custom field with similar purposes) :
|
|
||||||
|
|
||||||
.. code-block:: scala
|
.. code-block:: scala
|
||||||
|
|
||||||
@@ -49,6 +47,11 @@ use their default values, although it is recommended to use them if you need a c
|
|||||||
val name: Option[String] // Name of the core
|
val name: Option[String] // Name of the core
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class InstantiableTileParams[TileType <: BaseTile] extends TileParams {
|
||||||
|
def instantiate(crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)
|
||||||
|
(implicit p: Parameters): TileType
|
||||||
|
}
|
||||||
|
|
||||||
trait CoreParams {
|
trait CoreParams {
|
||||||
val bootFreqHz: BigInt // Frequency
|
val bootFreqHz: BigInt // Frequency
|
||||||
val useVM: Boolean // Support virtual memory
|
val useVM: Boolean // Support virtual memory
|
||||||
@@ -87,7 +90,7 @@ use their default values, although it is recommended to use them if you need a c
|
|||||||
def hasSupervisorMode: Boolean = useSupervisor || useVM
|
def hasSupervisorMode: Boolean = useSupervisor || useVM
|
||||||
def instBytes: Int = instBits / 8
|
def instBytes: Int = instBits / 8
|
||||||
def fetchBytes: Int = fetchWidth * instBytes
|
def fetchBytes: Int = fetchWidth * instBytes
|
||||||
// Rocket specific: Longest possible latency of Rocket core D1 cache. Simply set it to the default value 80.
|
// Rocket specific: Longest possible latency of Rocket core D1 cache. Simply set it to the default value 80 if you don't use it.
|
||||||
def lrscCycles: Int
|
def lrscCycles: Int
|
||||||
|
|
||||||
def dcacheReqTagBits: Int = 6
|
def dcacheReqTagBits: Int = 6
|
||||||
@@ -111,12 +114,21 @@ Most of the fields here are originally designed for Rocket core and contains som
|
|||||||
many of them are general enough to be useful for other cores. It is strongly recommended to use these fields instead
|
many of them are general enough to be useful for other cores. It is strongly recommended to use these fields instead
|
||||||
of creating your own custom fields when applicable.
|
of creating your own custom fields when applicable.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Implementations may choose to ignore some fields here or use them in a non-standard way, but using an inaccurate
|
||||||
|
value may break Chipyard components that rely on them (e.g. inaccurate indication of supported ISA extension will
|
||||||
|
result in incorrect test suite being generated) as well as any custom module that use them. ALWAYS document any
|
||||||
|
fields you ignore or with altered usage in your core implementation, and if you are implementing other devices that
|
||||||
|
would look up these config values, also document them. "Rocket specific" values are generally safe to ignore, but
|
||||||
|
you should document them if you use them.
|
||||||
|
|
||||||
Tile Class
|
Tile Class
|
||||||
----------
|
----------
|
||||||
|
|
||||||
In Chipyard, all connections with other components on SoC are defined a core's `Tile` class, while the implementation
|
In Chipyard, all Tiles are diplomatically instantiated. In the first phase, diplomatic nodes which specify Tile-to-System
|
||||||
of the actual hardware are in the implementation class. This structure allows Chipyard to use the Diplomacy framework
|
interconnects are evaluated, while in the second "Module Implementation" phase, hardware is elaborated.
|
||||||
to resolve paramters and connections before elaboration.
|
See :ref:`tilelink_and_diplomacy` for more details.
|
||||||
|
|
||||||
All tile classes implement ``BaseTile`` and will normally implement ``SinksExternalInterrupts`` and ``SourcesExternalNotifications``,
|
All tile classes implement ``BaseTile`` and will normally implement ``SinksExternalInterrupts`` and ``SourcesExternalNotifications``,
|
||||||
which allow the tile to accept external interrupt. A typical tile has the following form:
|
which allow the tile to accept external interrupt. A typical tile has the following form:
|
||||||
@@ -169,7 +181,8 @@ TileLink Connection
|
|||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Chipyard use TileLink as its onboard bus protocol, and if your core doesn't use TileLink, you will need to convert them
|
Chipyard use TileLink as its onboard bus protocol, and if your core doesn't use TileLink, you will need to convert them
|
||||||
in the tile class. Below is an example of how to connect a core using AXI4 to the TileLink bus:
|
in the tile class. Below is an example of how to connect a core using AXI4 to the TileLink bus with converters provided by
|
||||||
|
Chipyards:
|
||||||
|
|
||||||
.. code-block:: scala
|
.. code-block:: scala
|
||||||
|
|
||||||
@@ -185,9 +198,12 @@ in the tile class. Below is an example of how to connect a core using AXI4 to th
|
|||||||
:= memAXI4Node) // The custom node, see below
|
:= memAXI4Node) // The custom node, see below
|
||||||
|
|
||||||
Remember, you may not need all of these intermediate widgets. See :ref:`diplomatic_widgets` for the meaning of each intermediate
|
Remember, you may not need all of these intermediate widgets. See :ref:`diplomatic_widgets` for the meaning of each intermediate
|
||||||
widget. If you are using TileLink, then you only need the tap node and the TileLink node used by your components. Also, Chipyard
|
widget. If you are using TileLink, then you only need the tap node and the TileLink node used by your components. Chipyard also
|
||||||
support AHB, APB and AXIS, and most of the AXI4 widgets has equivalent widget for these bus protocol. See the reference page for
|
provides converters for AHB, APB and AXIS, and most of the AXI4 widgets has equivalent widget for these bus protocol; see the
|
||||||
more info.
|
source files in ``generators/rocket-chip/src/main/scala/amba`` for more info.
|
||||||
|
|
||||||
|
If you are using other bus protocol, you may implement your own converters, using the files in ``generators/rocket-chip/src/main/scala/amba``
|
||||||
|
as the template, but it is not recommended unless you are familiar with TileLink.
|
||||||
|
|
||||||
``memAXI4Node`` is an AXI4 master node and is defined as following in our example:
|
``memAXI4Node`` is an AXI4 master node and is defined as following in our example:
|
||||||
|
|
||||||
@@ -232,7 +248,8 @@ The definition of ``TileInterrupts`` is
|
|||||||
}
|
}
|
||||||
|
|
||||||
This function should be in the implementation class since it involves hardware generation.
|
This function should be in the implementation class since it involves hardware generation.
|
||||||
Also, the tile can also notify other cores or devices for some events by calling following functions (in implementation class):
|
Also, the tile can also notify other cores or devices for some events by calling following functions in ``SourcesExternalNotifications``
|
||||||
|
from the implementation class:
|
||||||
|
|
||||||
.. code-block:: scala
|
.. code-block:: scala
|
||||||
|
|
||||||
@@ -241,39 +258,6 @@ Also, the tile can also notify other cores or devices for some events by calling
|
|||||||
reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating)
|
reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating)
|
||||||
reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruction is executed
|
reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruction is executed
|
||||||
|
|
||||||
Trace (Optional)
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Chipyard provides a set of ports for instruction trace that conforms with related RISC-V standard.
|
|
||||||
If you are using FireSim, it is recommended to implement these trace ports to enable FireSim to read trace.
|
|
||||||
|
|
||||||
There are one inbound node ``traceAuxSinkNode.bundle: TraceAux`` and two outbound nodes ``traceCoreSourceNode.bundle: TraceCoreInterface``
|
|
||||||
and ``bpwatchSourceNode.bundle: Vec[BPWatch]``. Note that the length of ``bpwatchSourceNode`` is equal to the max number of
|
|
||||||
breakpoints (set by ``nBreakpoints`` in ``CoreParams``). Below is the definition of these types:
|
|
||||||
|
|
||||||
.. code-block:: scala
|
|
||||||
|
|
||||||
// Control signal from the external tracer
|
|
||||||
class TraceAux extends Bundle {
|
|
||||||
val enable = Bool() // Enable trace output
|
|
||||||
val stall = Bool() // If true, the core should stall
|
|
||||||
}
|
|
||||||
// Check RISC-V Processor Trace spec V1.0 for more information of this interface
|
|
||||||
class TraceCoreInterface (val params: TraceCoreParams) extends Bundle {
|
|
||||||
val group = Vec(params.nGroups, new TraceCoreGroup(params))
|
|
||||||
val priv = UInt(4.W)
|
|
||||||
val tval = UInt(params.xlen.W)
|
|
||||||
val cause = UInt(params.xlen.W)
|
|
||||||
}
|
|
||||||
// Address Breakpoint and watchpoint info (n is the retire width)
|
|
||||||
class BPWatch (val n: Int) extends Bundle() {
|
|
||||||
val valid = Vec(n, Bool()) // Valid bit of the output
|
|
||||||
val rvalid = Vec(n, Bool()) // Break on read
|
|
||||||
val wvalid = Vec(n, Bool()) // Break on write
|
|
||||||
val ivalid = Vec(n, Bool()) // Break on execute
|
|
||||||
val action = UInt(3.W) // Exception code (3 usually)
|
|
||||||
}
|
|
||||||
|
|
||||||
Implementation Class
|
Implementation Class
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@@ -313,12 +297,13 @@ the current config. An example of such config will be like this:
|
|||||||
|
|
||||||
.. code-block:: scala
|
.. code-block:: scala
|
||||||
|
|
||||||
class WithNMyCores(n: Int) extends Config((site, here, up) => {
|
class WithNMyCores(n: Int, hartidOffset: Int) extends Config((site, here, up) => {
|
||||||
case MyTilesKey => {
|
case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem)) :++ List.tabulate(n)(i => MyTileParams(hartId = i + hartidOffset))
|
||||||
List.tabulate(n)(i => MyTileParams(hartId = i))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Chipyard looks up the tile parameters in the field ``TilesLocated(InSubsystem)``, whose type is a list of ``InstantiableTileParams``.
|
||||||
|
This config fragment simply appends new tile parameters to the end of this list.
|
||||||
|
|
||||||
Now you have finished all the steps to prepare your cores for Chipyard! To generate the custom core, simply follow the instructions
|
Now you have finished all the steps to prepare your cores for Chipyard! To generate the custom core, simply follow the instructions
|
||||||
in :ref:`custom_chisel` to add your project to the build system, then create a config by following the steps in :ref:`hetero_socs_`.
|
in :ref:`custom_chisel` to add your project to the build system, then create a config by following the steps in :ref:`hetero_socs_`.
|
||||||
You can now run any desired workflow for the new config just as you do for the built-in cores.
|
You can now run any desired workflow for the new config just as you do for the built-in cores.
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
.. _tilelink_and_diplomacy:
|
||||||
|
|
||||||
TileLink and Diplomacy Reference
|
TileLink and Diplomacy Reference
|
||||||
================================
|
================================
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user