Merge branch 'dev' into diplomatic-clocks

This commit is contained in:
Jerry Zhao
2020-07-21 11:21:51 -07:00
18 changed files with 649 additions and 162 deletions

View File

@@ -104,7 +104,7 @@ $(TOP_TARGETS) $(HARNESS_TARGETS): firrtl_temp
@echo "" > /dev/null
firrtl_temp: $(FIRRTL_FILE) $(ANNO_FILE) $(VLOG_SOURCES)
$(call run_scala_main,tapeout,barstools.tapeout.transforms.GenerateTopAndHarness,-o $(TOP_FILE) -tho $(HARNESS_FILE) -i $(FIRRTL_FILE) --syn-top $(TOP) --harness-top $(VLOG_MODEL) -faf $(ANNO_FILE) -tsaof $(TOP_ANNO) -tdf $(sim_top_blackboxes) -tsf $(TOP_FIR) -thaof $(HARNESS_ANNO) -hdf $(sim_harness_blackboxes) -thf $(HARNESS_FIR) $(REPL_SEQ_MEM) $(HARNESS_CONF_FLAGS) -td $(build_dir)) && touch $(sim_top_blackboxes) $(sim_harness_blackboxes)
$(call run_scala_main,tapeout,barstools.tapeout.transforms.GenerateTopAndHarness,-o $(TOP_FILE) -tho $(HARNESS_FILE) -i $(FIRRTL_FILE) --syn-top $(TOP) --harness-top $(VLOG_MODEL) -faf $(ANNO_FILE) -tsaof $(TOP_ANNO) -tdf $(sim_top_blackboxes) -tsf $(TOP_FIR) -thaof $(HARNESS_ANNO) -hdf $(sim_harness_blackboxes) -thf $(HARNESS_FIR) $(REPL_SEQ_MEM) $(HARNESS_CONF_FLAGS) -td $(build_dir) -ll $(FIRRTL_LOGLEVEL)) && touch $(sim_top_blackboxes) $(sim_harness_blackboxes)
# DOC include end: FirrtlCompiler
# This file is for simulation only. VLSI flows should replace this file with one containing hard SRAMs

View File

@@ -0,0 +1,301 @@
.. _custom_core:
Adding a custom core
====================
You may want to integrate a custom RISC-V core into the Chipyard framework. This documentation page provides step-by-step
instructions on how to achieve this.
.. note::
RoCC is currently not supported by cores other than Rocket and BOOM. Please use Rocket or BOOM as the RoCC base core if you need to use RoCC.
.. note::
This page contains links to the files that contains important definitions in the Rocket chip repository, which is maintained separately
from Chipyard. If you find any discrepancy between the code on this page and the code in the source file, please report it through
GitHub issues!
Wrap Verilog Module with Blackbox (Optional)
--------------------------------------------
Since Chipyard uses Scala and Chisel, if the top module of your core is not in Chisel, you will first need to create a Verilog
blackbox for it so that it can be processed by Chipyard. See :ref:`incorporating-verilog-blocks` for instructions.
Create Parameter Case Classes
-----------------------------
Chipyard will generate a core for every ``InstantiableTileParams`` object it discovered in the ``TilesLocated(InSubsystem)`` key.
This object is derived from``TileParams``, a trait containing the information needed to create a tile. All cores must have
their own implementation of ``InstantiableTileParams``, as well as ``CoreParams`` which is passed as a field in ``TileParams``.
``TileParams`` holds the parameters for the tile, which include parameters for all components in the tile (e.g.
core, cache, MMU, etc.), while ``CoreParams`` contains parameters specific to the core on the tile.
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
variable to be implemented. You can also add custom fields to them, but standard fields should always be preferred.
``InstantiableTileParams[TileType]`` holds the constructor of ``TileType`` on top of the fields of ``TileParams``,
where ``TileType`` is the tile class (see the next section).
All custom cores will also need to implement ``instantiate()`` in their tile parameter class to return a new instance
of the tile class ``TileType``.
``TileParams`` (in the file `BaseTile.scala <https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/BaseTile.scala>`_) ,
``InstantiableTileParams`` (in the file `BaseTile.scala <https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/BaseTile.scala>`_),
``CoreParams`` (in the file `Core.scala <https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/Core.scala>`_),
and ``FPUParams`` (in the file `FPU.scala <https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/FPU.scala>`_)
contains the following fields:
.. code-block:: scala
trait TileParams {
val core: CoreParams // Core parameters (see below)
val icache: Option[ICacheParams] // Rocket specific: I1 cache option
val dcache: Option[DCacheParams] // Rocket specific: D1 cache option
val btb: Option[BTBParams] // Rocket specific: BTB / branch predictor option
val hartId: Int // Hart ID: Must be unique within a design config (This MUST be a case class parameter)
val beuAddr: Option[BigInt] // Rocket specific: Bus Error Unit for Rocket Core
val blockerCtrlAddr: Option[BigInt] // Rocket specific: Bus Blocker for Rocket 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 {
val bootFreqHz: BigInt // Frequency
val useVM: Boolean // Support virtual memory
val useUser: Boolean // Support user mode
val useSupervisor: Boolean // Support supervisor mode
val useDebug: Boolean // Support RISC-V debug specs
val useAtomics: Boolean // Support A extension
val useAtomicsOnlyForIO: Boolean // Support A extension for memory-mapped IO (may be true even if useAtomics is false)
val useCompressed: Boolean // Support C extension
val useVector: Boolean = false // Support V extension
val useSCIE: Boolean // Support custom instructions (in custom-0 and custom-1)
val useRVE: Boolean // Use E base ISA
val mulDiv: Option[MulDivParams] // *Rocket specific: M extension related setting (Use Some(MulDivParams()) to indicate M extension supported)
val fpu: Option[FPUParams] // F and D extensions and related setting (see below)
val fetchWidth: Int // Max # of insts fetched every cycle
val decodeWidth: Int // Max # of insts decoded every cycle
val retireWidth: Int // Max # of insts retired every cycle
val instBits: Int // Instruction bits (if 32 bit and 64 bit are both supported, use 64)
val nLocalInterrupts: Int // # of local interrupts (see SiFive interrupt cookbook)
val nPMPs: Int // # of Physical Memory Protection units
val pmpGranularity: Int // Size of the smallest unit of region for PMP unit (must be power of 2)
val nBreakpoints: Int // # of hardware breakpoints supported (in RISC-V debug specs)
val useBPWatch: Boolean // Support hardware breakpoints
val nPerfCounters: Int // # of supported performance counters
val haveBasicCounters: Boolean // Support basic counters defined in the RISC-V counter extension
val haveFSDirty: Boolean // If true, the core will set FS field in mstatus CSR to dirty when appropriate
val misaWritable: Boolean // Support writable misa CSR (like variable instruction bits)
val haveCFlush: Boolean // Rocket specific: enables Rocket's custom instruction extension to flush the cache
val nL2TLBEntries: Int // # of L2 TLB entries
val mtvecInit: Option[BigInt] // mtvec CSR (of V extension) initial value
val mtvecWritable: Boolean // If mtvec CSR is writable
// Normally, you don't need to change these values (except lrscCycles)
def customCSRs(implicit p: Parameters): CustomCSRs = new CustomCSRs
def hasSupervisorMode: Boolean = useSupervisor || useVM
def instBytes: Int = instBits / 8
def fetchBytes: Int = fetchWidth * instBytes
// 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 dcacheReqTagBits: Int = 6
def minFLen: Int = 32
def vLen: Int = 0
def sLen: Int = 0
def eLen(xLen: Int, fLen: Int): Int = xLen max fLen
def vMemDataBits: Int = 0
}
case class FPUParams(
minFLen: Int = 32, // Minimum floating point length (no need to change)
fLen: Int = 64, // Maximum floating point length, use 32 if only single precision is supported
divSqrt: Boolean = true, // Div/Sqrt operation supported
sfmaLatency: Int = 3, // Rocket specific: Fused multiply-add pipeline latency (single precision)
dfmaLatency: Int = 4 // Rocket specific: Fused multiply-add pipeline latency (double precision)
)
Most of the fields here (marked "Rocket spcific") are originally designed for the Rocket core and thus contain some
implementation-specific details, but many of them are general enough to be useful for other cores. You may ignore
any fields marked "Rocket specific" and use their default values; however, if you need to store additional information
with meaning or usage similar to these "Rocket specific" fields, it is recommended to use these fields instead of
creating your own custom fields.
You will also need a ``CanAttachTile`` class to add the tile config into the config system, with the following format:
.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala
:language: scala
:start-after: DOC include start: CanAttachTile
:end-before: DOC include end: CanAttachTile
During elaboration, Chipyard will look for subclasses of ``CanAttachTile`` in the config system and instantiate a tile
from the parameters in this class for every such class it found.
.. 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. an inaccurate indication of supported ISA extension will
result in an incorrect test suite being generated) as well as any custom modules 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.
Create Tile Class
-----------------
In Chipyard, all Tiles are diplomatically instantiated. In the first phase, diplomatic nodes which specify Tile-to-System
interconnects are evaluated, while in the second "Module Implementation" phase, hardware is elaborated.
See :ref:`tilelink_and_diplomacy` for more details. In this step, you will need to implement a tile class for your core,
which specifies the constraints on the core's parameters and the connections with other diplomatic nodes. This class
usually contains Diplomacy/TileLink code only, and Chisel RTL code should not go here.
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:
.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala
:language: scala
:start-after: DOC include start: Tile class
:end-before: DOC include end: Tile class
Connect TileLink Buses
----------------------
Chipyard uses TileLink as its onboard bus protocol. If your core doesn't use TileLink, you will need to insert converters
between the core's memory protocol and TileLink within the Tile module.
in the tile class. Below is an example of how to connect a core using AXI4 to the TileLink bus with converters provided by
Rocket chip:
.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala
:language: scala
:start-after: DOC include start: AXI4 convert
:end-before: DOC include end: AXI4 convert
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. Chipyard also
provides converters for AHB, APB and AXIS, and most of the AXI4 widgets has equivalent widget for these bus protocol; see the
source files in ``generators/rocket-chip/src/main/scala/amba`` for more info.
If you are using some 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:
.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala
:language: scala
:start-after: DOC include start: AXI4 node
:end-before: DOC include end: AXI4 node
where ``portName`` and ``idBits`` (number of bits to represent a port ID) are the parameter provides by the tile.
Make sure to read :ref:`node_types` to check out what type of nodes Chipyard supports and their parameters!
Also, by default, there are boundary buffers for both master and slave connections to the bus when they are leaving the tile, and you
can override the following two functions to control how to buffer the bus requests/responses:
(You can find the definition of these two functions in the class ``BaseTile`` in the file
`BaseTile.scala <https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/BaseTile.scala>`_)
.. code-block:: scala
// By default, their value is "TLBuffer(BufferParams.none)".
protected def makeMasterBoundaryBuffers(implicit p: Parameters): TLBuffer
protected def makeSlaveBoundaryBuffers(implicit p: Parameters): TLBuffer
You can find more information on ``TLBuffer`` in :ref:`diplomatic_widgets`.
Create Implementation Class
---------------------------
The implementation class contains the parameterized, actual hardware that depends on the values resolved by the Diplomacy
framework according to the info provided in the Tile class. This class will normally contains Chisel RTL code. If your
core is in Verilog, you will need to instantiate the black box class that wraps your Verilog implementation and connect it with the buses
and other components. No Diplomacy/TileLink code should be in this class; you should only connect the IO signals in TileLink
interfaces or other diplomatically defined components, which are located in the tile class.
The implementation class for your core is of the following form:
.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala
:language: scala
:start-after: DOC include start: Implementation class
:end-before: DOC include end: Implementation class
If you create an AXI4 node (or equivalents), you will need to connect them to your core. You can connect a port like this:
.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala
:language: scala
:start-after: DOC include start: AXI4 connect
:end-before: DOC include end: AXI4 connect
Connect Interrupt
-----------------
Chipyard allows a tile to either receive interrupts from other devices or initiate interrupts to notify other cores/devices.
In the tile that inherited ``SinksExternalInterrupts``, one can create a ``TileInterrupts`` object (a Chisel bundle) and
call ``decodeCoreInterrupts()`` with the object as the argument. Note that you should call this function in the implementation
class since it returns a Chisel bundle used by RTL code. You can then read the interrupt bits from the ``TileInterrupts`` bundle
we create above. The definition of ``TileInterrupts``
(in the file `Interrupts.scala <https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/Interrupts.scala>`_) is
.. code-block:: scala
class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) {
val debug = Bool() // debug interrupt
val mtip = Bool() // Machine level timer interrupt
val msip = Bool() // Machine level software interrupt
val meip = Bool() // Machine level external interrupt
val seip = usingSupervisor.option(Bool()) // Valid only if supervisor mode is supported
val lip = Vec(coreParams.nLocalInterrupts, Bool()) // Local interrupts
}
Here is an example on how to connect these signals in the implementation class:
.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala
:language: scala
:start-after: DOC include start: connect interrupt
:end-before: DOC include end: connect interrupt
Also, the tile can also notify other cores or devices for some events by calling following functions in ``SourcesExternalNotifications``
from the implementation class:
(These functions can be found in in the trait ``SourcesExternalNotifications`` in the file
`Interrupts.scala <https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/Interrupts.scala>`_)
.. code-block:: scala
def reportHalt(could_halt: Option[Bool]) // Triggered when there is an unrecoverable hardware error (halt the machine)
def reportHalt(errors: Seq[CanHaveErrors]) // Varient for standard error bundle (Rocket specific: used only by cache when there's an ECC error)
def reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating)
def reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruction is executed
Here is an example on how to use these functions to raise interrupt.
.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala
:language: scala
:start-after: DOC include start: raise interrupt
:end-before: DOC include end: raise interrupt
Create Config Fragments to Integrate the Core
---------------------------------------------
To use your core in a Chipyard config, you will need a config fragment that will create a ``TileParams`` object of your core in
the current config. An example of such config will be like this:
.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala
:language: scala
:start-after: DOC include start: Config fragment
:end-before: DOC include end: Config fragment
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
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 most desired workflows for the new config just as you would for the built-in cores (depending on the functionality your core supports).
If you would like to see an example of a complete third-party Verilog core integrated into Chipyard, ``generators/ariane/src/main/scala/ArianeTile.scala``
provides a concrete example of the Ariane core. Note that this particular example includes additional nuances with respect to the interaction of the AXI
interface with the memory coherency system.

View File

@@ -1,3 +1,5 @@
.. _hetero_socs_:
Heterogeneous SoCs
===============================

View File

@@ -7,6 +7,8 @@ These guides will walk you through customization of your system-on-chip:
- How to include your custom Chisel sources in the Chipyard build system
- Adding custom core
- Adding custom RoCC accelerators to an existing Chipyard core (BOOM or Rocket)
- Adding custom MMIO widgets to the Chipyard memory system by Tilelink or AXI4, with custom Top-level IOs
@@ -35,6 +37,7 @@ We recommend reading all these pages in order. Hit next to get started!
Heterogeneous-SoCs
Custom-Chisel
Custom-Core
RoCC-or-MMIO
RoCC-Accelerators
MMIO-Peripherals

View File

@@ -1,3 +1,5 @@
.. _node_types:
TileLink Node Types
===================

View File

@@ -1,3 +1,5 @@
.. _diplomatic_widgets:
Diplomatic Widgets
==================

View File

@@ -1,3 +1,5 @@
.. _tilelink_and_diplomacy:
TileLink and Diplomacy Reference
================================

View File

@@ -25,7 +25,7 @@ import sifive.blocks.devices.gpio._
import sifive.blocks.devices.uart._
import sifive.blocks.devices.spi._
import chipyard.{BuildTop, BuildSystem, ClockDrivers, ChipyardClockKey}
import chipyard.{BuildTop, BuildSystem, ClockDrivers, ChipyardClockKey, TestSuitesKey, TestSuiteHelper}
// -----------------------
@@ -44,9 +44,9 @@ class WithGPIO extends Config((site, here, up) => {
})
// DOC include end: gpio config fragment
class WithUART extends Config((site, here, up) => {
class WithUART(baudrate: BigInt = 115200) extends Config((site, here, up) => {
case PeripheryUARTKey => Seq(
UARTParams(address = 0x54000000L, nTxEntries = 256, nRxEntries = 256))
UARTParams(address = 0x54000000L, nTxEntries = 256, nRxEntries = 256, initBaudRate = baudrate))
})
class WithSPIFlash(size: BigInt = 0x10000000) extends Config((site, here, up) => {
@@ -92,17 +92,19 @@ class WithMultiRoCC extends Config((site, here, up) => {
*
* @param harts harts to specify which will get a Hwacha
*/
class WithMultiRoCCHwacha(harts: Int*) extends Config((site, here, up) => {
case MultiRoCCKey => {
up(MultiRoCCKey, site) ++ harts.distinct.map{ i =>
(i -> Seq((p: Parameters) => {
val hwacha = LazyModule(new Hwacha()(p))
hwacha
}))
class WithMultiRoCCHwacha(harts: Int*) extends Config(
new chipyard.config.WithHwachaTest ++
new Config((site, here, up) => {
case MultiRoCCKey => {
up(MultiRoCCKey, site) ++ harts.distinct.map{ i =>
(i -> Seq((p: Parameters) => {
val hwacha = LazyModule(new Hwacha()(p)).suggestName("hwacha")
hwacha
}))
}
}
}
})
})
)
class WithTraceIO extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map {
@@ -137,6 +139,18 @@ class WithRocketDCacheScratchpad extends Config((site, here, up) => {
}
})
class WithHwachaTest extends Config((site, here, up) => {
case TestSuitesKey => (tileParams: Seq[TileParams], suiteHelper: TestSuiteHelper, p: Parameters) => {
up(TestSuitesKey).apply(tileParams, suiteHelper, p)
import hwacha.HwachaTestSuites._
suiteHelper.addSuites(rv64uv.map(_("p")))
suiteHelper.addSuites(rv64uv.map(_("vp")))
suiteHelper.addSuite(rv64sv("p"))
suiteHelper.addSuite(hwachaBmarks)
"SRC_EXTENSION = $(base_dir)/hwacha/$(src_path)/*.scala" + "\nDISASM_EXTENSION = --extension=hwacha"
}
})
// The default RocketChip BaseSubsystem drives its diplomatic clock graph
// with the implicit clocks of Subsystem. Don't do that, instead we extend
// the diplomacy graph upwards into the ChipTop, where we connect it to

View File

@@ -3,8 +3,8 @@ package chipyard
import scala.collection.mutable.{LinkedHashSet}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tile.{XLen}
import freechips.rocketchip.config.{Parameters}
import freechips.rocketchip.tile.{XLen, TileParams}
import freechips.rocketchip.config.{Parameters, Field, Config}
import freechips.rocketchip.system.{TestGeneration, RegressionTestSuite, RocketTestSuite}
import boom.common.{BoomTileAttachParams}
@@ -64,133 +64,51 @@ class TestSuiteHelper
def addSuites(s: Seq[RocketTestSuite]) { s.foreach(addSuite) }
/**
* Add BOOM tests (asm, bmark, regression)
* Add generic tests (asm, bmark, regression) for all cores.
*/
def addBoomTestSuites(implicit p: Parameters) = {
def addGenericTestSuites(tiles: Seq[TileParams])(implicit p: Parameters) = {
val xlen = p(XLen)
p(TilesLocated(InSubsystem)).find(_.tileParams.hartId == 0).map {
case tp: BoomTileAttachParams => {
val tileParams = tp.tileParams
val coreParams = tileParams.core
val vm = coreParams.useVM
val env = if (vm) List("p","v") else List("p")
coreParams.fpu foreach { case cfg =>
if (xlen == 32) {
addSuites(env.map(rv32uf))
if (cfg.fLen >= 64) {
addSuites(env.map(rv32ud))
}
} else if (cfg.fLen >= 64) {
tiles.find(_.hartId == 0).map { tileParams =>
val coreParams = tileParams.core
val vm = coreParams.useVM
val env = if (vm) List("p","v") else List("p")
coreParams.fpu foreach { case cfg =>
if (xlen == 32) {
addSuites(env.map(rv32uf))
if (cfg.fLen >= 64)
addSuites(env.map(rv32ud))
} else {
addSuite(rv32udBenchmarks)
addSuites(env.map(rv64uf))
if (cfg.fLen >= 64)
addSuites(env.map(rv64ud))
addSuites(env.map(rv64uf))
addSuite(rv32udBenchmarks)
}
}
if (coreParams.useAtomics) {
if (tileParams.dcache.flatMap(_.scratch).isEmpty) {
addSuites(env.map(if (xlen == 64) rv64ua else rv32ua))
} else {
addSuites(env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC))
}
}
if (coreParams.useCompressed) addSuites(env.map(if (xlen == 64) rv64uc else rv32uc))
val (rvi, rvu) =
if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u)
else ((if (vm) rv32i else rv32pi), rv32u)
addSuites(rvi.map(_("p")))
addSuites(rvu.map(_("p")))
addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env))))
addSuite(benchmarks)
addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames))
}
case _ =>
}
}
/**
* Add Rocket tests (asm, bmark, regression)
*/
def addRocketTestSuites(implicit p: Parameters) = {
val xlen = p(XLen)
p(TilesLocated(InSubsystem)).find(_.tileParams.hartId == 0).map {
case tp: RocketTileAttachParams => {
val tileParams = tp.tileParams
val coreParams = tileParams.core
val vm = coreParams.useVM
val env = if (vm) List("p","v") else List("p")
coreParams.fpu foreach { case cfg =>
if (xlen == 32) {
addSuites(env.map(rv32uf))
if (cfg.fLen >= 64)
addSuites(env.map(rv32ud))
} else {
addSuite(rv32udBenchmarks)
addSuites(env.map(rv64uf))
if (cfg.fLen >= 64)
addSuites(env.map(rv64ud))
}
}
if (coreParams.useAtomics) {
if (tileParams.dcache.flatMap(_.scratch).isEmpty)
addSuites(env.map(if (xlen == 64) rv64ua else rv32ua))
else
addSuites(env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC))
}
if (coreParams.useCompressed) addSuites(env.map(if (xlen == 64) rv64uc else rv32uc))
val (rvi, rvu) =
if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u)
else ((if (vm) rv32i else rv32pi), rv32u)
addSuites(rvi.map(_("p")))
addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env))))
addSuite(benchmarks)
addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames))
if (coreParams.useAtomics) {
if (tileParams.dcache.flatMap(_.scratch).isEmpty)
addSuites(env.map(if (xlen == 64) rv64ua else rv32ua))
else
addSuites(env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC))
}
case _ =>
}
}
if (coreParams.useCompressed) addSuites(env.map(if (xlen == 64) rv64uc else rv32uc))
val (rvi, rvu) =
if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u)
else ((if (vm) rv32i else rv32pi), rv32u)
/**
* Add Ariane tests (asm, bmark, regression)
*/
def addArianeTestSuites(implicit p: Parameters) = {
val xlen = p(XLen)
p(TilesLocated(InSubsystem)).find(_.tileParams.hartId == 0).map {
case tp: ArianeTileAttachParams => {
val tileParams = tp.tileParams
val coreParams = tileParams.core
val vm = coreParams.useVM
val env = if (vm) List("p","v") else List("p")
coreParams.fpu foreach { case cfg =>
if (xlen == 32) {
addSuites(env.map(rv32uf))
if (cfg.fLen >= 64)
addSuites(env.map(rv32ud))
} else {
addSuite(rv32udBenchmarks)
addSuites(env.map(rv64uf))
if (cfg.fLen >= 64)
addSuites(env.map(rv64ud))
}
}
if (coreParams.useAtomics) {
if (tileParams.dcache.flatMap(_.scratch).isEmpty)
addSuites(env.map(if (xlen == 64) rv64ua else rv32ua))
else
addSuites(env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC))
}
if (coreParams.useCompressed) addSuites(env.map(if (xlen == 64) rv64uc else rv32uc))
val (rvi, rvu) =
if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u)
else ((if (vm) rv32i else rv32pi), rv32u)
addSuites(rvi.map(_("p")))
addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env))))
addSuite(benchmarks)
addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames))
}
case _ =>
addSuites(rvi.map(_("p")))
addSuites(rvu.map(_("p")))
addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env))))
addSuite(benchmarks)
addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames))
}
}
}
/**
* Config key of custom test suite.
*/
case object TestSuitesKey extends Field[(Seq[TileParams], TestSuiteHelper, Parameters) => String]((tiles, helper, p) => {
helper.addGenericTestSuites(tiles)(p)
// Return an empty string as makefile additional snippets
""
})

View File

@@ -19,7 +19,6 @@ class LargeBoomConfig extends Config(
new chipyard.config.AbstractConfig)
class MegaBoomConfig extends Config(
new boom.common.WithBoomBranchPrintf ++
new boom.common.WithNMegaBooms(1) ++ // mega boom config
new chipyard.config.AbstractConfig)
@@ -28,6 +27,7 @@ class DualSmallBoomConfig extends Config(
new chipyard.config.AbstractConfig)
class HwachaLargeBoomConfig extends Config(
new chipyard.config.WithHwachaTest ++
new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator
new boom.common.WithNLargeBooms(1) ++
new chipyard.config.AbstractConfig)
@@ -43,4 +43,3 @@ class DromajoBoomConfig extends Config(
new chipyard.config.WithTraceIO ++ // enable the traceio
new boom.common.WithNSmallBooms(1) ++
new chipyard.config.AbstractConfig)

View File

@@ -13,6 +13,7 @@ class LargeBoomAndRocketConfig extends Config(
// DOC include start: BoomAndRocketWithHwacha
class HwachaLargeBoomAndHwachaRocketConfig extends Config(
new chipyard.config.WithHwachaTest ++
new hwacha.DefaultHwachaConfig ++ // add hwacha to all harts
new boom.common.WithNLargeBooms(1) ++ // add 1 boom core
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket core

View File

@@ -11,6 +11,7 @@ class RocketConfig extends Config(
new chipyard.config.AbstractConfig)
class HwachaRocketConfig extends Config(
new chipyard.config.WithHwachaTest ++
new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)

View File

@@ -0,0 +1,236 @@
package chipyard.example
import chisel3._
import chisel3.util._
import freechips.rocketchip.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.diplomaticobjectmodel.logicaltree.{LogicalTreeNode}
import freechips.rocketchip.rocket._
import freechips.rocketchip.subsystem.{RocketCrossingParams}
import freechips.rocketchip.tilelink._
import freechips.rocketchip.interrupts._
import freechips.rocketchip.util._
import freechips.rocketchip.tile._
import freechips.rocketchip.amba.axi4._
// Example parameter class copied from Ariane, not included in documentation but for compile check only
// If you are here for documentation, DO NOT copy MyCoreParams and MyTileParams directly - always figure
// out what parameters you need before you write the parameter class
case class MyCoreParams(
bootFreqHz: BigInt = BigInt(1700000000),
rasEntries: Int = 4,
btbEntries: Int = 16,
bhtEntries: Int = 16,
enableToFromHostCaching: Boolean = false,
) extends CoreParams {
val useVM: Boolean = true
val useUser: Boolean = true
val useSupervisor: Boolean = false
val useDebug: Boolean = true
val useAtomics: Boolean = true
val useAtomicsOnlyForIO: Boolean = false // copied from Rocket
val useCompressed: Boolean = true
override val useVector: Boolean = false
val useSCIE: Boolean = false
val useRVE: Boolean = false
val mulDiv: Option[MulDivParams] = Some(MulDivParams()) // copied from Rocket
val fpu: Option[FPUParams] = Some(FPUParams()) // copied fma latencies from Rocket
val nLocalInterrupts: Int = 0
val nPMPs: Int = 0 // TODO: Check
val pmpGranularity: Int = 4 // copied from Rocket
val nBreakpoints: Int = 0 // TODO: Check
val useBPWatch: Boolean = false
val nPerfCounters: Int = 29
val haveBasicCounters: Boolean = true
val haveFSDirty: Boolean = false
val misaWritable: Boolean = false
val haveCFlush: Boolean = false
val nL2TLBEntries: Int = 512 // copied from Rocket
val mtvecInit: Option[BigInt] = Some(BigInt(0)) // copied from Rocket
val mtvecWritable: Boolean = true // copied from Rocket
val instBits: Int = if (useCompressed) 16 else 32
val lrscCycles: Int = 80 // copied from Rocket
val decodeWidth: Int = 1 // TODO: Check
val fetchWidth: Int = 1 // TODO: Check
val retireWidth: Int = 2
}
// DOC include start: CanAttachTile
case class MyTileAttachParams(
tileParams: MyTileParams,
crossingParams: RocketCrossingParams
) extends CanAttachTile {
type TileType = MyTile
val lookup = PriorityMuxHartIdFromSeq(Seq(tileParams))
}
// DOC include end: CanAttachTile
case class MyTileParams(
name: Option[String] = Some("my_tile"),
hartId: Int = 0,
trace: Boolean = false,
val core: MyCoreParams = MyCoreParams()
) extends InstantiableTileParams[MyTile]
{
val beuAddr: Option[BigInt] = None
val blockerCtrlAddr: Option[BigInt] = None
val btb: Option[BTBParams] = Some(BTBParams())
val boundaryBuffers: Boolean = false
val dcache: Option[DCacheParams] = Some(DCacheParams())
val icache: Option[ICacheParams] = Some(ICacheParams())
def instantiate(crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters): MyTile = {
new MyTile(this, crossing, lookup)
}
}
// DOC include start: Tile class
class MyTile(
val myParams: MyTileParams,
crossing: ClockCrossingType,
lookup: LookupByHartIdImpl,
q: Parameters)
extends BaseTile(myParams, crossing, lookup, q)
with SinksExternalInterrupts
with SourcesExternalNotifications
{
// Private constructor ensures altered LazyModule.p is used implicitly
def this(params: MyTileParams, crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters) =
this(params, crossing.crossingType, lookup, p)
// Require TileLink nodes
val intOutwardNode = IntIdentityNode()
val masterNode = visibilityNode
val slaveNode = TLIdentityNode()
// Implementation class (See below)
override lazy val module = new MyTileModuleImp(this)
// Required entry of CPU device in the device tree for interrupt purpose
val cpuDevice: SimpleDevice = new SimpleDevice("cpu", Seq("my-organization,my-cpu", "riscv")) {
override def parent = Some(ResourceAnchors.cpus)
override def describe(resources: ResourceBindings): Description = {
val Description(name, mapping) = super.describe(resources)
Description(name, mapping ++
cpuProperties ++
nextLevelCacheProperty ++
tileProperties)
}
}
ResourceBinding {
Resource(cpuDevice, "reg").bind(ResourceAddress(hartId))
}
// TODO: Create TileLink nodes and connections here.
// DOC include end: Tile class
// DOC include start: AXI4 node
// # of bits used in TileLink ID for master node. 4 bits can support 16 master nodes, but you can have a longer ID if you need more.
val idBits = 4
val memAXI4Node = AXI4MasterNode(
Seq(AXI4MasterPortParameters(
masters = Seq(AXI4MasterParameters(
name = "myPortName",
id = IdRange(0, 1 << idBits))))))
val memoryTap = TLIdentityNode() // Every bus connection should have their own tap node
// DOC include end: AXI4 node
// DOC include start: AXI4 convert
(tlMasterXbar.node // tlMasterXbar is the bus crossbar to be used when this core / tile is acting as a master; otherwise, use tlSlaveXBar
:= memoryTap
:= TLBuffer()
:= TLFIFOFixer(TLFIFOFixer.all) // fix FIFO ordering
:= TLWidthWidget(masterPortBeatBytes) // reduce size of TL
:= AXI4ToTL() // convert to TL
:= AXI4UserYanker(Some(2)) // remove user field on AXI interface. need but in reality user intf. not needed
:= AXI4Fragmenter() // deal with multi-beat xacts
:= memAXI4Node) // The custom node, see below
// DOC include end: AXI4 convert
}
// DOC include start: Implementation class
class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){
// annotate the parameters
Annotated.params(this, outer.myParams)
// TODO: Create the top module of the core and connect it with the ports in "outer"
// If your core is in Verilog (assume your blackbox is called "MyCoreBlackbox"), instantiate it here like
// val core = Module(new MyCoreBlackbox(params...))
// (as described in the blackbox tutorial) and connect appropriate signals. See the blackbox tutorial
// (link on the top of the page) for more info.
// You can look at https://github.com/ucb-bar/ariane-wrapper/blob/master/src/main/scala/ArianeTile.scala
// for a Verilog example.
// If your core is in Chisel, you can simply instantiate the top module here like other Chisel module
// and connect appropriate signal. You can even implement this class as your top module.
// See https://github.com/riscv-boom/riscv-boom/blob/master/src/main/scala/common/tile.scala and
// https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/RocketTile.scala for
// Chisel example.
// DOC include end: Implementation class
// DOC include start: connect interrupt
// For example, our core support debug interrupt and machine-level interrupt, and suppose the following two signals
// are the interrupt inputs to the core. (DO NOT COPY this code - if your core treat each type of interrupt differently,
// you need to connect them to different interrupt ports of your core)
val debug_i = Wire(Bool())
val mtip_i = Wire(Bool())
// We create a bundle here and decode the interrupt.
val int_bundle = new TileInterrupts()
outer.decodeCoreInterrupts(int_bundle)
debug_i := int_bundle.debug
mtip_i := int_bundle.meip & int_bundle.msip & int_bundle.mtip
// DOC include end: connect interrupt
// DOC include start: raise interrupt
// This is a demo. You should call these function according to your core
// Suppose that the following signal is from the decoder indicating a WFI instruction is received.
val wfi_o = Wire(Bool())
outer.reportWFI(Some(wfi_o))
// Suppose that the following signal indicate an unreconverable hardware error.
val halt_o = Wire(Bool())
outer.reportHalt(Some(halt_o))
// Suppose that our core never stall for a long time / stop retiring. Use None to indicate that this interrupt never fires.
outer.reportCease(None)
// DOC include end: raise interrupt
// DOC include start: AXI4 connect
outer.memAXI4Node.out foreach { case (out, edgeOut) =>
// Connect your module IO port to "out"
// The type of "out" here is AXI4Bundle, which is defined in generators/rocket-chip/src/main/scala/amba/axi4/Bundles.scala
// Please refer to this file for the definition of the ports.
// If you are using APB, check APBBundle in generators/rocket-chip/src/main/scala/amba/apb/Bundles.scala
// If you are using AHB, check AHBSlaveBundle or AHBMasterBundle in generators/rocket-chip/src/main/scala/amba/ahb/Bundles.scala
// (choose one depends on the type of AHB node you create)
// If you are using AXIS, check AXISBundle and AXISBundleBits in generators/rocket-chip/src/main/scala/amba/axis/Bundles.scala
}
// DOC include end: AXI4 connect
}
// DOC include start: Config fragment
class WithNMyCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => {
// Calculate the next available hart ID (since hart ID cannot be duplicated)
val prev = up(TilesLocated(InSubsystem), site)
val idOffset = overrideIdOffset.getOrElse(prev.size)
// Create TileAttachParams for every core to be instantiated
(0 until n).map { i =>
MyTileAttachParams(
tileParams = MyTileParams(hartId = i + idOffset),
crossingParams = RocketCrossingParams()
)
} ++ prev
}
// Configurate # of bytes in one memory / IO transaction. For RV64, one load/store instruction can transfer 8 bytes at most.
case SystemBusKey => up(SystemBusKey, site).copy(beatBytes = 8)
// The # of instruction bits. Use maximum # of bits if your core supports both 32 and 64 bits.
case XLen => 64
})
// DOC include end: Config fragment

View File

@@ -15,14 +15,16 @@ import firrtl.options.Viewer.view
import freechips.rocketchip.stage.RocketChipOptions
import freechips.rocketchip.stage.phases.{RocketTestSuiteAnnotation}
import freechips.rocketchip.system.{RocketTestSuite, TestGeneration}
import freechips.rocketchip.subsystem.{TilesLocated, InSubsystem}
import freechips.rocketchip.util.HasRocketChipStageUtils
import freechips.rocketchip.tile.XLen
import chipyard.TestSuiteHelper
import chipyard.TestSuitesKey
class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils {
// Make sure we run both after RocketChip's version of this phase, and Rocket Chip's annotation emission phase
// because the RocketTestSuiteAnnotation is not serializable (but is not marked as such).
// because the RocketTestSuiteAnnotation is not serializable (but is not marked as such).
override val prerequisites = Seq(
Dependency[freechips.rocketchip.stage.phases.GenerateFirrtlAnnos],
Dependency[freechips.rocketchip.stage.phases.AddDefaultTests])
@@ -33,25 +35,11 @@ class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipS
val suiteHelper = new TestSuiteHelper
// Use Xlen as a proxy for detecting if we are a processor-like target
// The underlying test suites expect this field to be defined
if (p.lift(XLen).nonEmpty) {
suiteHelper.addRocketTestSuites
suiteHelper.addBoomTestSuites
suiteHelper.addArianeTestSuites
}
val tileParams = p(TilesLocated(InSubsystem)) map (tp => tp.tileParams)
if (p.lift(XLen).nonEmpty)
// If a custom test suite is set up, use the custom test suite
annotations += CustomMakefragSnippet(p(TestSuitesKey).apply(tileParams, suiteHelper, p))
// if hwacha parameter exists then generate its tests
// TODO: find a more elegant way to do this. either through
// trying to disambiguate BuildRoCC, having a AccelParamsKey,
// or having the Accelerator/Tile add its own tests
import hwacha.HwachaTestSuites._
if (Try(p(hwacha.HwachaNLanes)).getOrElse(0) > 0) {
suiteHelper.addSuites(rv64uv.map(_("p")))
suiteHelper.addSuites(rv64uv.map(_("vp")))
suiteHelper.addSuite(rv64sv("p"))
suiteHelper.addSuite(hwachaBmarks)
annotations += CustomMakefragSnippet(
"SRC_EXTENSION = $(base_dir)/hwacha/$(src_path)/*.scala" + "\nDISASM_EXTENSION = --extension=hwacha")
}
RocketTestSuiteAnnotation(suiteHelper.suites.values.toSeq) +: annotations
}

View File

@@ -70,7 +70,8 @@ class WithFireSimConfigTweaks extends Config(
new WithFireSimSimpleClocks ++
// Required*: When using FireSim-as-top to provide a correct path to the target bootrom source
new WithBootROM ++
// Optional*: Removing this will require target-software changes to properly capture UART output
// Optional*: Removing this will require adjusting the UART baud rate and
// potential target-software changes to properly capture UART output
new WithPeripheryBusFrequency(BigInt(3200000000L)) ++
// Required: Existing FAME-1 transform cannot handle black-box clock gates
new WithoutClockGating ++
@@ -86,8 +87,8 @@ class WithFireSimConfigTweaks extends Config(
new testchipip.WithTSI ++
// Optional: Removing this will require using an initramfs under linux
new testchipip.WithBlockDevice ++
// Required*:
new chipyard.config.WithUART
// Required*: Scale default baud rate with periphery bus frequency
new chipyard.config.WithUART(BigInt(3686400L))
)
/*******************************************************************************
@@ -118,6 +119,21 @@ class FireSimQuadRocketConfig extends Config(
new WithFireSimConfigTweaks ++
new chipyard.QuadRocketConfig)
// A stripped down configuration that should fit on all supported hosts.
// Flat to avoid having to reorganize the config class hierarchy to remove certain features
class FireSimSmallSystemConfig extends Config(
new WithDefaultFireSimBridges ++
new WithDefaultMemModel ++
new WithBootROM ++
new WithPeripheryBusFrequency(BigInt(3200000000L)) ++
new WithoutClockGating ++
new WithoutTLMonitors ++
new freechips.rocketchip.subsystem.WithExtMemSize(1 << 28) ++
new testchipip.WithTSI ++
new testchipip.WithBlockDevice ++
new chipyard.config.WithUART ++
new freechips.rocketchip.subsystem.WithInclusiveCache(nWays = 2, capacityKB = 64) ++
new chipyard.RocketConfig)
//*****************************************************************
// Boom config, base off chipyard's LargeBoomConfig

View File

@@ -152,6 +152,8 @@ define run_scala_main
endef
endif
FIRRTL_LOGLEVEL ?= error
#########################################################################################
# output directory for tests
#########################################################################################