From ac5235e5ed6225b6fb5d8f00a45d035a0e53cf2a Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Tue, 21 Jan 2020 20:44:54 -0800 Subject: [PATCH] Revamp the config system for Top/Harness (#347) * Refactor how Configs parameterize the Top and TestHarnesses * Bump sha3, testchipip, icenet, firesim --- .circleci/defaults.sh | 2 +- docs/Advanced-Concepts/CDEs.rst | 111 ++++++++ docs/Advanced-Concepts/index.rst | 2 + docs/Chipyard-Basics/index.rst | 1 + docs/Customization/Adding-An-Accelerator.rst | 261 ------------------ docs/Customization/Custom-Chisel.rst | 59 ++++ docs/Customization/DMA-Devices.rst | 39 +++ .../Incorporating-Verilog-Blocks.rst | 51 +--- docs/Customization/Keys-Traits-Configs.rst | 106 +++++++ docs/Customization/MMIO-Peripherals.rst | 142 ++++++++++ docs/Customization/RoCC-Accelerators.rst | 70 +++++ docs/Customization/RoCC-or-MMIO.rst | 27 ++ docs/Customization/index.rst | 31 ++- docs/Generators/Gemmini.rst | 2 +- docs/Generators/SHA3.rst | 2 +- docs/Generators/SiFive-Generators.rst | 10 +- docs/Quick-Start.rst | 2 +- .../src/main/resources/vsrc/GCDMMIOBlackBox.v | 4 +- .../example/src/main/scala/BoomConfigs.scala | 46 ++- .../example/src/main/scala/ConfigMixins.scala | 151 ++++------ generators/example/src/main/scala/GCD.scala | 200 ++++++++++++++ .../src/main/scala/GCDMMIOBlackBox.scala | 98 ------- .../src/main/scala/HeteroConfigs.scala | 45 ++- .../example/src/main/scala/InitZero.scala | 16 +- generators/example/src/main/scala/PWM.scala | 134 --------- .../src/main/scala/RocketConfigs.scala | 117 +++++--- .../example/src/main/scala/TestHarness.scala | 57 +--- generators/example/src/main/scala/Top.scala | 108 ++------ .../src/main/scala/BridgeBinders.scala | 10 +- .../src/main/scala/TargetConfigs.scala | 12 +- .../firechip/src/main/scala/Targets.scala | 21 +- generators/icenet | 2 +- generators/sha3 | 2 +- generators/testchipip | 2 +- sims/firesim | 2 +- 35 files changed, 1087 insertions(+), 858 deletions(-) create mode 100644 docs/Advanced-Concepts/CDEs.rst delete mode 100644 docs/Customization/Adding-An-Accelerator.rst create mode 100644 docs/Customization/Custom-Chisel.rst create mode 100644 docs/Customization/DMA-Devices.rst create mode 100644 docs/Customization/Keys-Traits-Configs.rst create mode 100644 docs/Customization/MMIO-Peripherals.rst create mode 100644 docs/Customization/RoCC-Accelerators.rst create mode 100644 docs/Customization/RoCC-or-MMIO.rst create mode 100644 generators/example/src/main/scala/GCD.scala delete mode 100644 generators/example/src/main/scala/GCDMMIOBlackBox.scala delete mode 100644 generators/example/src/main/scala/PWM.scala diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index 87a761d9..c5838a48 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -45,7 +45,7 @@ mapping["example"]="SUB_PROJECT=example" mapping["boomrocketexample"]="SUB_PROJECT=example CONFIG=LargeBoomAndRocketConfig" mapping["boom"]="SUB_PROJECT=example CONFIG=SmallBoomConfig" mapping["rocketchip"]="SUB_PROJECT=rocketchip" -mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=SimBlockDeviceRocketConfig TOP=TopWithBlockDevice" +mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=SimBlockDeviceRocketConfig" mapping["hwacha"]="SUB_PROJECT=example CONFIG=HwachaRocketConfig" mapping["gemmini"]="SUB_PROJECT=example CONFIG=GemminiRocketConfig" mapping["tracegen"]="SUB_PROJECT=tracegen CONFIG=NonBlockingTraceGenL2Config" diff --git a/docs/Advanced-Concepts/CDEs.rst b/docs/Advanced-Concepts/CDEs.rst new file mode 100644 index 00000000..b8e130e6 --- /dev/null +++ b/docs/Advanced-Concepts/CDEs.rst @@ -0,0 +1,111 @@ +.. _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 mixins until it finds a partial function which is defined at the key, and then returns that value. + +.. code:: scala + + val params = Config(new WithX(true) ++ new WithY(true)) // "chain" together mixins + 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. + +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 = Config(new WithXEqualsYSite ++ new WithY(true)) + val params_2 = 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 = Config(new WithXEqualsYHere ++ new WithY(true)) + val params_2 = 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 = Config(new WithXEqualsYUp ++ new WithY(true)) + val params_2 = 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 mixins were used*. Since the order of mixins 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``. + + diff --git a/docs/Advanced-Concepts/index.rst b/docs/Advanced-Concepts/index.rst index 8194fe1f..af23525a 100644 --- a/docs/Advanced-Concepts/index.rst +++ b/docs/Advanced-Concepts/index.rst @@ -12,3 +12,5 @@ They expect you to know about Chisel, Parameters, Configs, etc. Chip-Communication Debugging-RTL Resources + CDEs + diff --git a/docs/Chipyard-Basics/index.rst b/docs/Chipyard-Basics/index.rst index 28a08700..9a306c4f 100644 --- a/docs/Chipyard-Basics/index.rst +++ b/docs/Chipyard-Basics/index.rst @@ -16,6 +16,7 @@ Hit next to get started! :caption: Chipyard Basics: Chipyard-Components + Development-Ecosystem Configs-Parameters-Mixins Initial-Repo-Setup diff --git a/docs/Customization/Adding-An-Accelerator.rst b/docs/Customization/Adding-An-Accelerator.rst deleted file mode 100644 index 3c0ea4eb..00000000 --- a/docs/Customization/Adding-An-Accelerator.rst +++ /dev/null @@ -1,261 +0,0 @@ -.. _adding-an-accelerator: - -Adding an Accelerator/Device -=============================== - -Accelerators or custom IO devices can be added to your SoC in several ways: - -* MMIO Peripheral (a.k.a TileLink-Attached Accelerator) -* Tightly-Coupled RoCC Accelerator - -These approaches differ in the method of the communication between the processor and the custom block. - -With the TileLink-Attached approach, the processor communicates with MMIO peripherals through memory-mapped registers. - -In contrast, the processor communicates with a RoCC accelerators through a custom protocol and custom non-standard ISA instructions reserved in the RISC-V ISA encoding space. -Each core can have up to four accelerators that are controlled by custom instructions and share resources with the CPU. -RoCC coprocessor instructions have the following form. - -.. code-block:: none - - customX rd, rs1, rs2, funct - -The X will be a number 0-3, and determines the opcode of the instruction, which controls which accelerator an instruction will be routed to. -The ``rd``, ``rs1``, and ``rs2`` fields are the register numbers of the destination register and two source registers. -The ``funct`` field is a 7-bit integer that the accelerator can use to distinguish different instructions from each other. - -Note that communication through a RoCC interface requires a custom software toolchain, whereas MMIO peripherals can use that standard toolchain with appropriate driver support. - -Integrating into the Generator Build System -------------------------------------------- - -While developing, you want to include Chisel code in a submodule so that it can be shared by different projects. -To add a submodule to the Chipyard framework, make sure that your project is organized as follows. - -.. code-block:: none - - yourproject/ - build.sbt - src/main/scala/ - YourFile.scala - -Put this in a git repository and make it accessible. -Then add it as a submodule to under the following directory hierarchy: ``generators/yourproject``. - -.. code-block:: shell - - cd generators/ - git submodule add https://git-repository.com/yourproject.git - -Then add ``yourproject`` to the Chipyard top-level build.sbt file. - -.. code-block:: scala - - lazy val yourproject = (project in file("generators/yourproject")).settings(commonSettings).dependsOn(rocketchip) - -You can then import the classes defined in the submodule in a new project if -you add it as a dependency. For instance, if you want to use this code in -the ``example`` project, change the final line in build.sbt to the following. - -.. code-block:: scala - - lazy val example = (project in file(".")).settings(commonSettings).dependsOn(testchipip, yourproject) - -MMIO Peripheral ------------------- - -The easiest way to create a TileLink peripheral is to use the ``TLRegisterRouter``, which abstracts away the details of handling the TileLink protocol and provides a convenient interface for specifying memory-mapped registers. -To create a RegisterRouter-based peripheral, you will need to specify a parameter case class for the configuration settings, a bundle trait with the extra top-level ports, and a module implementation containing the actual RTL. -In this case we use a submodule ``PWMBase`` to actually perform the pulse-width modulation. The ``PWMModule`` class only creates the registers and hooks them -up using ``regmap``. - -.. literalinclude:: ../../generators/example/src/main/scala/PWM.scala - :language: scala - :start-after: DOC include start: PWM generic traits - :end-before: DOC include end: PWM generic traits - -Once you have these classes, you can construct the final peripheral by extending the ``TLRegisterRouter`` and passing the proper arguments. -The first set of arguments determines where the register router will be placed in the global address map and what information will be put in its device tree entry. -The second set of arguments is the IO bundle constructor, which we create by extending ``TLRegBundle`` with our bundle trait. -The final set of arguments is the module constructor, which we create by extends ``TLRegModule`` with our module trait. - -.. literalinclude:: ../../generators/example/src/main/scala/PWM.scala - :language: scala - :start-after: DOC include start: PWMTL - :end-before: DOC include end: PWMTL - -The full module code can be found in ``generators/example/src/main/scala/PWM.scala``. - -After creating the module, we need to hook it up to our SoC. -Rocket Chip accomplishes this using the cake pattern. -This basically involves placing code inside traits. -In the Rocket Chip cake, there are two kinds of traits: a ``LazyModule`` trait and a module implementation trait. - -The ``LazyModule`` trait runs setup code that must execute before all the hardware gets elaborated. -For a simple memory-mapped peripheral, this just involves connecting the peripheral's TileLink node to the MMIO crossbar. - -.. literalinclude:: ../../generators/example/src/main/scala/PWM.scala - :language: scala - :start-after: DOC include start: HasPeripheryPWMTL - :end-before: DOC include end: HasPeripheryPWMTL - -Note that the ``PWMTL`` class we created from the register router is itself a ``LazyModule``. -Register routers have a TileLink node simply named "node", which we can hook up to the Rocket Chip bus. -This will automatically add address map and device tree entries for the peripheral. - -The module implementation trait is where we instantiate our PWM module and connect it to the rest of the SoC. -Since this module has an extra `pwmout` output, we declare that in this trait, using Chisel's multi-IO functionality. -We then connect the ``PWMTL``'s pwmout to the pwmout we declared. - -.. literalinclude:: ../../generators/example/src/main/scala/PWM.scala - :language: scala - :start-after: DOC include start: HasPeripheryPWMTLModuleImp - :end-before: DOC include end: HasPeripheryPWMTLModuleImp - -Now we want to mix our traits into the system as a whole. -This code is from ``generators/example/src/main/scala/Top.scala``. - -.. literalinclude:: ../../generators/example/src/main/scala/Top.scala - :language: scala - :start-after: DOC include start: TopWithPWMTL - :end-before: DOC include end: TopWithPWMTL - -Just as we need separate traits for ``LazyModule`` and module implementation, we need two classes to build the system. -The ``Top`` classes already have the basic peripherals included for us, so we will just extend those. - -The ``Top`` class includes the pre-elaboration code and also a ``lazy val`` to produce the module implementation (hence ``LazyModule``). -The ``TopModule`` class is the actual RTL that gets synthesized. - -Next, we need to add a configuration mixin in ``generators/example/src/main/scala/ConfigMixins.scala`` that tells the ``TestHarness`` to instantiate ``TopWithPWMTL`` instead of the default ``Top``. - -.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala - :language: scala - :start-after: DOC include start: WithPWMTop - :end-before: DOC include end: WithPWMTop - -And finally, we create a configuration class in ``generators/example/src/main/scala/Configs.scala`` that uses this mixin. - -.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala - :language: scala - :start-after: DOC include start: PWMRocketConfig - :end-before: DOC include end: PWMRocketConfig - -Now we can test that the PWM is working. The test program is in ``tests/pwm.c``. - -.. literalinclude:: ../../tests/pwm.c - :language: c - -This just writes out to the registers we defined earlier. -The base of the module's MMIO region is at 0x2000. -This will be printed out in the address map portion when you generated the verilog code. - -Compiling this program with make produces a ``pwm.riscv`` executable. - -Now with all of that done, we can go ahead and run our simulation. - -.. code-block:: shell - - cd sims/verilator - make CONFIG=PWMRocketConfig TOP=TopWithPWMTL - ./simulator-example-PWMRocketConfig ../../tests/pwm.riscv - -Adding a RoCC Accelerator ----------------------------- - -RoCC accelerators are lazy modules that extend the ``LazyRoCC`` class. -Their implementation should extends the ``LazyRoCCModule`` class. - -.. code-block:: scala - - class CustomAccelerator(opcodes: OpcodeSet) - (implicit p: Parameters) extends LazyRoCC(opcodes) { - override lazy val module = new CustomAcceleratorModule(this) - } - - class CustomAcceleratorModule(outer: CustomAccelerator) - extends LazyRoCCModuleImp(outer) { - val cmd = Queue(io.cmd) - // The parts of the command are as follows - // inst - the parts of the instruction itself - // opcode - // rd - destination register number - // rs1 - first source register number - // rs2 - second source register number - // funct - // xd - is the destination register being used? - // xs1 - is the first source register being used? - // xs2 - is the second source register being used? - // rs1 - the value of source register 1 - // rs2 - the value of source register 2 - ... - } - - -The ``opcodes`` parameter for ``LazyRoCC`` is the set of custom opcodes that will map to this accelerator. -More on this in the next subsection. - -The ``LazyRoCC`` class contains two TLOutputNode instances, ``atlNode`` and ``tlNode``. -The former connects into a tile-local arbiter along with the backside of the L1 instruction cache. -The latter connects directly to the L1-L2 crossbar. -The corresponding Tilelink ports in the module implementation's IO bundle are ``atl`` and ``tl``, respectively. - -The other interfaces available to the accelerator are ``mem``, which provides access to the L1 cache; -``ptw`` which provides access to the page-table walker; -the ``busy`` signal, which indicates when the accelerator is still handling an instruction; -and the ``interrupt`` signal, which can be used to interrupt the CPU. - -Look at the examples in ``generators/rocket-chip/src/main/scala/tile/LazyRocc.scala`` for detailed information on the different IOs. - -Adding RoCC accelerator to Config -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -RoCC accelerators can be added to a core by overriding the ``BuildRoCC`` parameter in the configuration. -This takes a sequence of functions producing ``LazyRoCC`` objects, one for each accelerator you wish to add. - -For instance, if we wanted to add the previously defined accelerator and route custom0 and custom1 instructions to it, we could do the following. - -.. code-block:: scala - - class WithCustomAccelerator extends Config((site, here, up) => { - case BuildRoCC => Seq((p: Parameters) => LazyModule( - new CustomAccelerator(OpcodeSet.custom0 | OpcodeSet.custom1)(p))) - }) - - class CustomAcceleratorConfig extends Config( - new WithCustomAccelerator ++ new RocketConfig) - -To add RoCC instructions in your program, use the RoCC C macros provided in ``tests/rocc.h``. You can find examples in the files ``tests/accum.c`` and ``charcount.c``. - -Adding a DMA port -------------------- - -For IO devices or accelerators (like a disk or network driver), instead of -having the CPU poll data from the device, we may want to have the device write -directly to the coherent memory system instead. For example, here is a device -that writes zeros to the memory at a configured address. - -.. literalinclude:: ../../generators/example/src/main/scala/InitZero.scala - :language: scala - -.. literalinclude:: ../../generators/example/src/main/scala/Top.scala - :language: scala - :start-after: DOC include start: TopWithInitZero - :end-before: DOC include end: TopWithInitZero - -We use ``TLHelper.makeClientNode`` to create a TileLink client node for us. -We then connect the client node to the memory system through the front bus (fbus). -For more info on creating TileLink client nodes, take a look at :ref:`Client Node`. - -Once we've created our top-level module including the DMA widget, we can create a configuration for it as we did before. - -.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala - :language: scala - :start-after: DOC include start: WithInitZero - :end-before: DOC include end: WithInitZero - -.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala - :language: scala - :start-after: DOC include start: InitZeroRocketConfig - :end-before: DOC include end: InitZeroRocketConfig - - diff --git a/docs/Customization/Custom-Chisel.rst b/docs/Customization/Custom-Chisel.rst new file mode 100644 index 00000000..feec3141 --- /dev/null +++ b/docs/Customization/Custom-Chisel.rst @@ -0,0 +1,59 @@ +.. _custom_chisel: + +Integrating Custom Chisel Projects into the Generator Build System +================================================================== + +.. warning:: + This section assumes integration of custom Chisel through git submodules. + While it is possible to directly commit custom Chisel into the Chipyard framework, + we heavily recommend managing custom code through git submodules. Using submodules decouples + development of custom features from development on the Chipyard framework. + + +While developing, you want to include Chisel code in a submodule so that it can be shared by different projects. +To add a submodule to the Chipyard framework, make sure that your project is organized as follows. + +.. code-block:: none + + yourproject/ + build.sbt + src/main/scala/ + YourFile.scala + +Put this in a git repository and make it accessible. +Then add it as a submodule to under the following directory hierarchy: ``generators/yourproject``. + +The ``build.sbt`` is a minimal file which describes metadata for a Chisel project. +For a simple project, the ``build.sbt`` can even be empty, but below we provide an example +build.sbt. + +.. code-block:: scala + + organization := "edu.berkeley.cs" + + version := "1.0" + + name := "yourproject" + + scalaVersion := "2.12.4" + + + +.. code-block:: shell + + cd generators/ + git submodule add https://git-repository.com/yourproject.git + +Then add ``yourproject`` to the Chipyard top-level build.sbt file. + +.. code-block:: scala + + lazy val yourproject = (project in file("generators/yourproject")).settings(commonSettings).dependsOn(rocketchip) + +You can then import the classes defined in the submodule in a new project if +you add it as a dependency. For instance, if you want to use this code in +the ``example`` project, change the final line in build.sbt to the following. + +.. code-block:: scala + + lazy val example = (project in file(".")).settings(commonSettings).dependsOn(testchipip, yourproject) diff --git a/docs/Customization/DMA-Devices.rst b/docs/Customization/DMA-Devices.rst new file mode 100644 index 00000000..f2e95e52 --- /dev/null +++ b/docs/Customization/DMA-Devices.rst @@ -0,0 +1,39 @@ +.. _dma-devices: + +Adding a DMA Device +=================== + +DMA devices are Tilelink widgets which act as masters. In other words, +DMA devices can send their own read and write requests to the chip's memory +system. + +For IO devices or accelerators (like a disk or network driver), instead of +having the CPU poll data from the device, we may want to have the device write +directly to the coherent memory system instead. For example, here is a device +that writes zeros to the memory at a configured address. + +.. literalinclude:: ../../generators/example/src/main/scala/InitZero.scala + :language: scala + +.. literalinclude:: ../../generators/example/src/main/scala/Top.scala + :language: scala + :start-after: DOC include start: Top + :end-before: DOC include end: Top + +We use ``TLHelper.makeClientNode`` to create a TileLink client node for us. +We then connect the client node to the memory system through the front bus (fbus). +For more info on creating TileLink client nodes, take a look at :ref:`Client Node`. + +Once we've created our top-level module including the DMA widget, we can create a configuration for it as we did before. + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: WithInitZero + :end-before: DOC include end: WithInitZero + +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala + :language: scala + :start-after: DOC include start: InitZeroRocketConfig + :end-before: DOC include end: InitZeroRocketConfig + + diff --git a/docs/Customization/Incorporating-Verilog-Blocks.rst b/docs/Customization/Incorporating-Verilog-Blocks.rst index 64f064f8..48f0c6e3 100644 --- a/docs/Customization/Incorporating-Verilog-Blocks.rst +++ b/docs/Customization/Incorporating-Verilog-Blocks.rst @@ -8,8 +8,7 @@ design flows. Fortunately, both Chisel and Chipyard provide extensive support for Verilog integration. Here, we will examine the process of incorporating an MMIO peripheral -(similar to the PWM example from the previous section) that uses a -Verilog implementation of Greatest Common Denominator (GCD) +that uses a Verilog implementation of Greatest Common Denominator (GCD) algorithm. There are a few steps to adding a Verilog peripheral: * Adding a Verilog resource file to the project @@ -58,7 +57,7 @@ and Verilog sources follow the prescribed directory layout. build.sbt src/main/ scala/ - GCDMMIOBlackBox.scala + GCD.scala resources/ vsrc/ GCDMMIOBlackBox.v @@ -89,7 +88,7 @@ as the bitwidth of the GCD calculation does in this example. **Chisel BlackBox Definition** -.. literalinclude:: ../../generators/example/src/main/scala/GCDMMIOBlackBox.scala +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala :language: scala :start-after: DOC include start: GCD blackbox :end-before: DOC include end: GCD blackbox @@ -102,54 +101,32 @@ diplomatic memory mapping on the system bus, we still have to integrate the peripheral at the Chisel level by mixing peripheral-specific traits into a ``TLRegisterRouter``. The ``params`` member and ``HasRegMap`` base trait should look familiar from the -previous memory-mapped PWM device example. +previous memory-mapped GCD device example. -.. literalinclude:: ../../generators/example/src/main/scala/GCDMMIOBlackBox.scala +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala :language: scala :start-after: DOC include start: GCD instance regmap :end-before: DOC include end: GCD instance regmap -Advanced Features of RegField Entries -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -One significant difference from the PWM example is in the peripheral's -memory map. ``RegField`` exposes polymorphic ``r`` and ``w`` methods -that allow read- and write-only memory-mapped registers to be -interfaced to hardware in multiple ways. - -* ``RegField.r(2, status)`` is used to create a 2-bit, read-only register that captures the current value of the ``status`` signal when read. -* ``RegField.r(params.width, gcd)`` "connects" the decoupled handshaking interface ``gcd`` to a read-only memory-mapped register. When this register is read via MMIO, the ``ready`` signal is asserted. This is in turn connected to ``output_ready`` on the Verilog blackbox through the glue logic. -* ``RegField.w(params.width, x)`` exposes a plain register (much like those in the PWM example) via MMIO, but makes it write-only. -* ``RegField.w(params.width, y)`` associates the decoupled interface signal ``y`` with a write-only memory-mapped register, causing ``y.valid`` to be asserted when the register is written. - -Since the ready/valid signals of ``y`` are connected to the -``input_ready`` and ``input_valid`` signals of the blackbox, -respectively, this register map and glue logic has the effect of -triggering the GCD algorithm when ``y`` is written. Therefore, the -algorithm is set up by first writing ``x`` and then performing a -triggering write to ``y``. Polling can be used for status checks. - -Defining a Chip with a GCD Peripheral +Defining a Chip with a BlackBox --------------------------------------- -As with the PWM example, a few more pieces are needed to tie the system together. +Since we've parameterized the GCD instantiation to choose between the +Chisel and the verilog module, creating a config is easy. -**Composing traits into a complete cake pattern peripheral** - -.. literalinclude:: ../../generators/example/src/main/scala/GCDMMIOBlackBox.scala +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala :language: scala - :start-after: DOC include start: GCD cake - :end-before: DOC include end: GCD cake + :start-after: DOC include start: GCDAXI4BlackBoxRocketConfig + :end-before: DOC include end: GCDAXI4BlackBoxRocketConfig -Note the differences arising due to the fact that this peripheral has -no top-level IO. To build a complete system, a new ``Top`` and new -``Config`` objects are added in a manner exactly analogous to the PWM -example. +You can play with the parameterization of the mixin to choose a TL/AXI4, BlackBox/Chisel +version of the GCD. Software Testing ---------------- -The GCD module has a slightly more complex interface, so polling is +The GCD module has a more complex interface, so polling is used to check the status of the device before each triggering read or write. diff --git a/docs/Customization/Keys-Traits-Configs.rst b/docs/Customization/Keys-Traits-Configs.rst new file mode 100644 index 00000000..8184975f --- /dev/null +++ b/docs/Customization/Keys-Traits-Configs.rst @@ -0,0 +1,106 @@ +.. _keys-traits-configs: + +Keys, Traits, and Configs +========================= + +You have probably seen snippets of Chisel referencing Keys, Traits, and Configs by this point. +This section aims to elucidate the interactions between these Chisel/Scala components, and provide +best practices for how these should be used to create a parameterized design and configure it. + +We will continue to use the GCD example. + +Keys +---- + +Keys specify some parameter which controls some custom widget. Keys should typically be implemented as **Option types**, with a default value of ``None`` that means no change in the system. In other words, the default behavior when the user does not explicitly set the key should be a no-op. + +Keys should be defined and documented in sub-projects, since they generally deal with some specific block, and not system-level integration. (We make an exception for the example GCD widget). + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD key + :end-before: DOC include end: GCD key + +The object within a key is typically a ``case class XXXParams``, which defines a set of parameters which some block accepts. For example, the GCD widget's ``GCDParams`` parameterizes its address, operand widths, whether the widget should be connected by Tilelink or AXI4, and whether the widget should use the blackbox-verilog implementation, or the Chisel implementation. + + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD params + :end-before: DOC include end: GCD params + +Accessing the value stored in the key is easy in Chisel, as long as the ``implicit p: Parameters`` object is being passed through to the relevant module. For example, ``p(GCDKey).get.address`` returns the address field of ``GCDParams``. Note this only works if ``GCDKey`` was not set to ``None``, so your Chisel should check for that case! + +Traits +------ + +Typically, most custom blocks will need to modify the behavior of some pre-existing block. For example, the GCD widget needs the ``Top`` module to instantiate and connect the widget via Tilelink, generate a top-level ``gcd_busy`` port, and connect that to the module as well. Traits let us do this without modifying the existing code for the ``Top``, and enables compartmentalization of code for different custom blocks. + +Top-level traits specify that the ``Top`` has been parameterized to read some custom Key and optionally instantiate and connect a widget defined by that Key. Traits **should not** mandate the instantiation of custom logic. In other words, traits should be written with ``CanHave`` semantics, where the default behavior when the Key is unset is a no-op. + +Top-level traits should be defined and documented in subprojects, alongside their corresponding Keys. The traits should then be added to the ``Top`` being used by Chipyard. + +Below we see the traits for the GCD example. The Lazy trait connects the GCD module to the Diplomacy graph, while the Implementation trait causes the ``Top`` to instantiate an additional port and concretely connect it to the GCD module. + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD lazy trait + :end-before: DOC include end: GCD imp trait + +These traits are added to the default ``Top`` in Chipyard. + +.. literalinclude:: ../../generators/example/src/main/scala/Top.scala + :language: scala + :start-after: DOC include start: Top + :end-before: DOC include end: Top + +Mixins +------ + +Mixins set the keys to a non-default value. Together, the collection of Mixins which define a configuration generate the values for all the keys used by the generator. + +For example, the ``WithGCDMixin`` is parameterized by the type of GCD widget you want to instantiate. When this mixin is added to a config, the ``GCDKey`` is set to a instance of ``GCDParams``, informing the previously mentioned traits to instantiate and connect the GCD widget appropriately. + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: GCD mixin + :end-before: DOC include end: GCD mixin + +We can use this mixin when composing our configs. + +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala + :language: scala + :start-after: DOC include start: GCDTLRocketConfig + :end-before: DOC include end: GCDTLRocketConfig + + +BuildTop +-------- + +The ``BuildTop`` key is special, because sometimes, we need to instantiate ``TestHarness`` modules to interface with a custom widget. The ``BuildTop`` key provides a function which can call some method of the Top to instantiate these ``TestHarness`` modules. Since the ``BuildTop`` key is called from the ``TestHarness``, these modules will appear in the ``TestHarness``. The config system also lets the ``BuildTop`` key look recursively into previous definitions of itself. This enables composability of the ``Top`` configurations. + +For example, conside a config that contains the mixins ``WithGPIO ++ WithTSI``. We need to instantiate the TSI serial adapter, and connect it to the ``success`` signal of our ``TestHarness``. We also need to instantiate the GPIO pins, and tie their inputs to 0 in the ``TestHarness``, since we currently cannot drive the GPIOs in simulation. + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: tsi mixin + :end-before: DOC include end: tsi mixin + + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: gpio mixin + :end-before: DOC include end: gpio mixin + +When ``WithGPIO ++ WithTSI`` is evaluated right to left, the call to ``up(BuildTop, site)`` in ``WithGPIO`` will reference the function defined in the ``BuildTop`` key of ``WithTSI``. Thus, at elaboration time, when the ``BuildTop`` function is called by the ``TestHarness``, first the ``BuildTop`` function in ``WithTSI`` will be evaluated. This connects the ``success`` signal of the ``TestHarness`` to the ``SerialAdapter`` enabled by ``WithTSI``. Then, the rest of the code in the ``BuildTop`` function of ``WithGPIO`` will execute, tieing off the top-level GPIO input pins. Thus the evaluation of the ``BuildTop`` functions in a completed config is "right-to-left", matching how the evaluation of the mixins at compile-time is also "right-to-left". + +.. warning:: + Note that in some cases, the ordering and duplication of mixins which extend ``BuildTop`` will have unintended consequences. + For example, ``WithTSI ++ WithTSI`` will attempt to generate and connect two ``SimSerial`` widgets in the ``TestHarness``, + which will likely break the simulation. + In general, you should avoid attaching multiple mixins which interface to the same top-level ports. + +.. note:: + Readers who want more information on the configuration system may be interested in reading :ref:`cdes`. + + diff --git a/docs/Customization/MMIO-Peripherals.rst b/docs/Customization/MMIO-Peripherals.rst new file mode 100644 index 00000000..0e01edb5 --- /dev/null +++ b/docs/Customization/MMIO-Peripherals.rst @@ -0,0 +1,142 @@ +.. _mmio-accelerators: + +MMIO Peripherals +================== + +The easiest way to create a MMIO peripheral is to use the ``TLRegisterRouter`` or ``AXI4RegisterRouter`` widgets, which abstracts away the details of handling the interconnect protocols and provides a convenient interface for specifying memory-mapped registers. Since Chipyard and Rocket Chip SoCs primarily use Tilelink as the on-chip interconnect protocol, this section will primarily focus on designing Tilelink-based peripherals. However, see ``generators/example/src/main/scala/GCD.scala`` for how an example AXI4 based peripheral is defined and connected to the Tilelink graph through converters. + +To create a RegisterRouter-based peripheral, you will need to specify a parameter case class for the configuration settings, a bundle trait with the extra top-level ports, and a module implementation containing the actual RTL. + +For this example, we will show how to connect a MMIO peripheral which computes the GCD. +The full code can be found in ``generators/example/src/main/scala/GCD.scala``. + +In this case we use a submodule ``GCDMMIOChiselModule`` to actually perform the GCD. The ``GCDModule`` class only creates the registers and hooks them up using ``regmap``. + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD chisel + :end-before: DOC include end: GCD chisel + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD instance regmap + :end-before: DOC include end: GCD instance regmap + +Advanced Features of RegField Entries +------------------------------------- + +``RegField`` exposes polymorphic ``r`` and ``w`` methods +that allow read- and write-only memory-mapped registers to be +interfaced to hardware in multiple ways. + +* ``RegField.r(2, status)`` is used to create a 2-bit, read-only register that captures the current value of the ``status`` signal when read. +* ``RegField.r(params.width, gcd)`` "connects" the decoupled handshaking interface ``gcd`` to a read-only memory-mapped register. When this register is read via MMIO, the ``ready`` signal is asserted. This is in turn connected to ``output_ready`` on the GCD module through the glue logic. +* ``RegField.w(params.width, x)`` exposes a plain register via MMIO, but makes it write-only. +* ``RegField.w(params.width, y)`` associates the decoupled interface signal ``y`` with a write-only memory-mapped register, causing ``y.valid`` to be asserted when the register is written. + +Since the ready/valid signals of ``y`` are connected to the +``input_ready`` and ``input_valid`` signals of the GCD module, +respectively, this register map and glue logic has the effect of +triggering the GCD algorithm when ``y`` is written. Therefore, the +algorithm is set up by first writing ``x`` and then performing a +triggering write to ``y``. Polling can be used for status checks. + + +Connecting by TileLink +---------------------- + +Once you have these classes, you can construct the final peripheral by extending the ``TLRegisterRouter`` and passing the proper arguments. +The first set of arguments determines where the register router will be placed in the global address map and what information will be put in its device tree entry. +The second set of arguments is the IO bundle constructor, which we create by extending ``TLRegBundle`` with our bundle trait. +The final set of arguments is the module constructor, which we create by extends ``TLRegModule`` with our module trait. +Notice how we can create an analogous AXI4 version of our peripheral. + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD router + :end-before: DOC include end: GCD router + + + +Top-level Traits +---------------- + +After creating the module, we need to hook it up to our SoC. +Rocket Chip accomplishes this using the cake pattern. +This basically involves placing code inside traits. +In the Rocket Chip cake, there are two kinds of traits: a ``LazyModule`` trait and a module implementation trait. + +The ``LazyModule`` trait runs setup code that must execute before all the hardware gets elaborated. +For a simple memory-mapped peripheral, this just involves connecting the peripheral's TileLink node to the MMIO crossbar. + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD lazy trait + :end-before: DOC include end: GCD lazy trait + +Note that the ``GCDTL`` class we created from the register router is itself a ``LazyModule``. +Register routers have a TileLink node simply named "node", which we can hook up to the Rocket Chip bus. +This will automatically add address map and device tree entries for the peripheral. +Also observe how we have to place additional AXI4 buffers and converters for the AXI4 version of this peripheral. + +For peripherals which instantiate a concrete module, or which need to be connected to concrete IOs or wires, a matching concrete trait is necessary. We will make our GCD example output a ``gcd_busy`` signal as a top-level port to demonstrate. In the concrete module implementation trait, we instantiate the top level IO (a concrete object) and wire it to the IO of our lazy module. + + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD imp trait + :end-before: DOC include end: GCD imp trait + +Constructing the Top and Config +------------------------------- + +Now we want to mix our traits into the system as a whole. +This code is from ``generators/example/src/main/scala/Top.scala``. + +.. literalinclude:: ../../generators/example/src/main/scala/Top.scala + :language: scala + :start-after: DOC include start: Top + :end-before: DOC include end: Top + +Just as we need separate traits for ``LazyModule`` and module implementation, we need two classes to build the system. +The ``Top`` class contains the set of traits which parameterize and define the ``Top``. Typically these traits will optionally add IOs or peripherals to the ``Top``. +The ``Top`` class includes the pre-elaboration code and also a ``lazy val`` to produce the module implementation (hence ``LazyModule``). +The ``TopModule`` class is the actual RTL that gets synthesized. + + + +And finally, we create a configuration class in ``generators/example/src/main/scala/Configs.scala`` that uses the ``WithGCD`` mixin defined earlier. + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: GCD mixin + :end-before: DOC include end: GCD mixin + +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala + :language: scala + :start-after: DOC include start: GCDTLRocketConfig + :end-before: DOC include end: GCDTLRocketConfig + +Testing +------- + +Now we can test that the GCD is working. The test program is in ``tests/gcd.c``. + +.. literalinclude:: ../../tests/gcd.c + :language: c + +This just writes out to the registers we defined earlier. +The base of the module's MMIO region is at 0x2000 by default. +This will be printed out in the address map portion when you generate the verilog code. +You can also see how this changes the emitted ``.json`` addressmap files in ``generated-src``. + +Compiling this program with ``make`` produces a ``gcd.riscv`` executable. + +Now with all of that done, we can go ahead and run our simulation. + +.. code-block:: shell + + cd sims/verilator + make CONFIG=GCDTLRocketConfig BINARY=../../tests/gcd.riscv run-binary + + diff --git a/docs/Customization/RoCC-Accelerators.rst b/docs/Customization/RoCC-Accelerators.rst new file mode 100644 index 00000000..7a3f4447 --- /dev/null +++ b/docs/Customization/RoCC-Accelerators.rst @@ -0,0 +1,70 @@ +.. _rocc-accelerators: + +Adding a RoCC Accelerator +---------------------------- + +RoCC accelerators are lazy modules that extend the ``LazyRoCC`` class. +Their implementation should extends the ``LazyRoCCModule`` class. + +.. code-block:: scala + + class CustomAccelerator(opcodes: OpcodeSet) + (implicit p: Parameters) extends LazyRoCC(opcodes) { + override lazy val module = new CustomAcceleratorModule(this) + } + + class CustomAcceleratorModule(outer: CustomAccelerator) + extends LazyRoCCModuleImp(outer) { + val cmd = Queue(io.cmd) + // The parts of the command are as follows + // inst - the parts of the instruction itself + // opcode + // rd - destination register number + // rs1 - first source register number + // rs2 - second source register number + // funct + // xd - is the destination register being used? + // xs1 - is the first source register being used? + // xs2 - is the second source register being used? + // rs1 - the value of source register 1 + // rs2 - the value of source register 2 + ... + } + + +The ``opcodes`` parameter for ``LazyRoCC`` is the set of custom opcodes that will map to this accelerator. +More on this in the next subsection. + +The ``LazyRoCC`` class contains two TLOutputNode instances, ``atlNode`` and ``tlNode``. +The former connects into a tile-local arbiter along with the backside of the L1 instruction cache. +The latter connects directly to the L1-L2 crossbar. +The corresponding Tilelink ports in the module implementation's IO bundle are ``atl`` and ``tl``, respectively. + +The other interfaces available to the accelerator are ``mem``, which provides access to the L1 cache; +``ptw`` which provides access to the page-table walker; +the ``busy`` signal, which indicates when the accelerator is still handling an instruction; +and the ``interrupt`` signal, which can be used to interrupt the CPU. + +Look at the examples in ``generators/rocket-chip/src/main/scala/tile/LazyRocc.scala`` for detailed information on the different IOs. + +Adding RoCC accelerator to Config +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +RoCC accelerators can be added to a core by overriding the ``BuildRoCC`` parameter in the configuration. +This takes a sequence of functions producing ``LazyRoCC`` objects, one for each accelerator you wish to add. + +For instance, if we wanted to add the previously defined accelerator and route custom0 and custom1 instructions to it, we could do the following. + +.. code-block:: scala + + class WithCustomAccelerator extends Config((site, here, up) => { + case BuildRoCC => Seq((p: Parameters) => LazyModule( + new CustomAccelerator(OpcodeSet.custom0 | OpcodeSet.custom1)(p))) + }) + + class CustomAcceleratorConfig extends Config( + new WithCustomAccelerator ++ + new RocketConfig) + +To add RoCC instructions in your program, use the RoCC C macros provided in ``tests/rocc.h``. You can find examples in the files ``tests/accum.c`` and ``charcount.c``. + diff --git a/docs/Customization/RoCC-or-MMIO.rst b/docs/Customization/RoCC-or-MMIO.rst new file mode 100644 index 00000000..dd1ed81c --- /dev/null +++ b/docs/Customization/RoCC-or-MMIO.rst @@ -0,0 +1,27 @@ +.. _rocc-vs-mmio: + +RoCC vs MMIO +------------ + +Accelerators or custom IO devices can be added to your SoC in several ways: + +* MMIO Peripheral (a.k.a TileLink-Attached Accelerator) +* Tightly-Coupled RoCC Accelerator + +These approaches differ in the method of the communication between the processor and the custom block. + +With the TileLink-Attached approach, the processor communicates with MMIO peripherals through memory-mapped registers. + +In contrast, the processor communicates with a RoCC accelerators through a custom protocol and custom non-standard ISA instructions reserved in the RISC-V ISA encoding space. +Each core can have up to four accelerators that are controlled by custom instructions and share resources with the CPU. +RoCC coprocessor instructions have the following form. + +.. code-block:: none + + customX rd, rs1, rs2, funct + +The X will be a number 0-3, and determines the opcode of the instruction, which controls which accelerator an instruction will be routed to. +The ``rd``, ``rs1``, and ``rs2`` fields are the register numbers of the destination register and two source registers. +The ``funct`` field is a 7-bit integer that the accelerator can use to distinguish different instructions from each other. + +Note that communication through a RoCC interface requires a custom software toolchain, whereas MMIO peripherals can use that standard toolchain with appropriate driver support. diff --git a/docs/Customization/index.rst b/docs/Customization/index.rst index cd52a499..c76c1f3f 100644 --- a/docs/Customization/index.rst +++ b/docs/Customization/index.rst @@ -3,18 +3,41 @@ Customization These guides will walk you through customization of your system-on-chip: -- Contructing heterogenous systems-on-chip using the Chipyard generators and configuration system. +- Contructing heterogenous systems-on-chip using the existing Chipyard generators and configuration system. -- Adding custom accelerators to your system-on-chip. +- How to include your custom Chisel sources in the Chipyard build system -Hit next to get started! +- 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 + +- Standard practices for using Keys, Traits, and Configs to parameterize your design + +- Customizing the memory hierarchy + +- Connect widgets which act as TileLink masters + +- Adding custom blackboxed verilog to a Chipyard design + +We also provide information on: + +- The boot process for Chipyard SoCs + +- Examples of FIRRTL transforms used in Chipyard, and where they are specified + +We recommend reading all these pages in order. Hit next to get started! .. toctree:: :maxdepth: 2 :caption: Customization: Heterogeneous-SoCs - Adding-An-Accelerator + Custom-Chisel + RoCC-or-MMIO + RoCC-Accelerators + MMIO-Peripherals + Keys-Traits-Configs + DMA-Devices Incorporating-Verilog-Blocks Memory-Hierarchy Boot-Process diff --git a/docs/Generators/Gemmini.rst b/docs/Generators/Gemmini.rst index d90e6224..66f8e017 100644 --- a/docs/Generators/Gemmini.rst +++ b/docs/Generators/Gemmini.rst @@ -56,7 +56,7 @@ The ``software`` directory of the generator includes the aforementioned library The Gemmini generator generates a C header file based on the generator parameters. This header files gets compiled together with the matrix multiplication library to tune library performance. The generated header file can be found under ``software/gemmini-rocc-tests/include/gemmini_params.h`` Build and Run Gemmini Tests -^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^ To build Gemmini tests: diff --git a/docs/Generators/SHA3.rst b/docs/Generators/SHA3.rst index a61e7e82..a9b87108 100644 --- a/docs/Generators/SHA3.rst +++ b/docs/Generators/SHA3.rst @@ -78,6 +78,6 @@ this mixin is shown here: :end-before: DOC include end: Sha3Rocket The SHA3 example baremetal and Linux tests are located in the SHA3 repository. -Please refer to its `README.md`__ for more information on how to run/build the tests. +Please refer to its `README.md `_ for more information on how to run/build the tests. diff --git a/docs/Generators/SiFive-Generators.rst b/docs/Generators/SiFive-Generators.rst index 8f2202b0..19360162 100644 --- a/docs/Generators/SiFive-Generators.rst +++ b/docs/Generators/SiFive-Generators.rst @@ -20,17 +20,11 @@ To integrate one of these devices in your SoC, you will need to define a custom .. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala :language: scala - :start-after: DOC include start: WithGPIO - :end-before: DOC include end: WithGPIO + :start-after: DOC include start: gpio mixin + :end-before: DOC include end: gpio mixin Additionally, if the device requires top-level IOs, you will need to define a mixin to change the top-level configuration of your SoC. When adding a top-level IO, you should also be aware of whether it interacts with the test-harness. -For example, a GPIO device would require a GPIO pin, and therefore we would write a mixin to augment the top level as follows: - -.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala - :language: scala - :start-after: DOC include start: WithGPIOTop - :end-before: DOC include end: WithGPIOTop This example instantiates a top-level module with include GPIO ports (``TopWithGPIO``), and then ties-off the GPIO port inputs to 0 (``false.B``). diff --git a/docs/Quick-Start.rst b/docs/Quick-Start.rst index d1d7ed93..cc650bd6 100644 --- a/docs/Quick-Start.rst +++ b/docs/Quick-Start.rst @@ -54,7 +54,7 @@ This depends on what you are planning to do with Chipyard. * If you intend to run a full-system FireSim simulation, go to :ref:`firesim-sim-intro` and follow the instructions. -* If you intend to add a new accelerator, go to :ref:`adding-an-accelerator` and follow the instructions. +* If you intend to add a new accelerator, go to :ref:`customization` and follow the instructions. * If you want to learn about the structure of Chipyard, go to :ref:`chipyard-components`. diff --git a/generators/example/src/main/resources/vsrc/GCDMMIOBlackBox.v b/generators/example/src/main/resources/vsrc/GCDMMIOBlackBox.v index 9104ae87..46acd5c8 100644 --- a/generators/example/src/main/resources/vsrc/GCDMMIOBlackBox.v +++ b/generators/example/src/main/resources/vsrc/GCDMMIOBlackBox.v @@ -10,7 +10,8 @@ module GCDMMIOBlackBox input [WIDTH-1:0] y, input output_ready, output output_valid, - output reg [WIDTH-1:0] gcd + output reg [WIDTH-1:0] gcd, + output busy ); // DOC include end: GCD portlist @@ -21,6 +22,7 @@ module GCDMMIOBlackBox assign input_ready = state == S_IDLE; assign output_valid = state == S_DONE; + assign busy = state != S_IDLE; always @(posedge clock) begin if (reset) diff --git a/generators/example/src/main/scala/BoomConfigs.scala b/generators/example/src/main/scala/BoomConfigs.scala index 0f1535ea..a6a0adb4 100644 --- a/generators/example/src/main/scala/BoomConfigs.scala +++ b/generators/example/src/main/scala/BoomConfigs.scala @@ -9,54 +9,72 @@ import freechips.rocketchip.config.{Config} // --------------------- class SmallBoomConfig extends Config( - new WithTop ++ // use normal top + new WithTSI ++ // use testchipip serial offchip link + new WithNoGPIO ++ // no top-level GPIO pins (overrides default set in sifive-blocks) new WithBootROM ++ // use testchipip bootrom new WithUART ++ // add a UART + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level mmio master port (overrides default set in rocketchip) + new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level mmio slave port (overrides default set in rocketchip) new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use SiFive L2 cache new boom.common.WithSmallBooms ++ // 1-wide BOOM new boom.common.WithNBoomCores(1) ++ // single-core new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system class MediumBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithMediumBooms ++ // 2-wide BOOM new boom.common.WithNBoomCores(1) ++ new freechips.rocketchip.system.BaseConfig) class LargeBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithLargeBooms ++ // 3-wide BOOM new boom.common.WithNBoomCores(1) ++ new freechips.rocketchip.system.BaseConfig) class MegaBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithMegaBooms ++ // 4-wide BOOM new boom.common.WithNBoomCores(1) ++ new freechips.rocketchip.system.BaseConfig) class DualSmallBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithSmallBooms ++ new boom.common.WithNBoomCores(2) ++ // dual-core new freechips.rocketchip.system.BaseConfig) class SmallRV32BoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithoutBoomFPU ++ // no fp new boom.common.WithBoomRV32 ++ // rv32 (32bit) @@ -65,9 +83,12 @@ class SmallRV32BoomConfig extends Config( new freechips.rocketchip.system.BaseConfig) class HwachaLargeBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator new boom.common.WithLargeBooms ++ // 3-wide BOOM @@ -75,11 +96,16 @@ class HwachaLargeBoomConfig extends Config( new freechips.rocketchip.system.BaseConfig) class LoopbackNICBoomConfig extends Config( - new WithIceNIC ++ - new WithLoopbackNICTop ++ + new WithTSI ++ + new WithNoGPIO ++ + new WithLoopbackNIC ++ // loopback the NIC + new WithIceNIC ++ // add IceNIC new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new boom.common.WithLargeBooms ++ // 3-wide BOOM + new boom.common.WithLargeBooms ++ new boom.common.WithNBoomCores(1) ++ new freechips.rocketchip.system.BaseConfig) + diff --git a/generators/example/src/main/scala/ConfigMixins.scala b/generators/example/src/main/scala/ConfigMixins.scala index 441a9289..b3deeb3f 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -7,8 +7,10 @@ import freechips.rocketchip.config.{Field, Parameters, Config} import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, WithRoccExample, WithNMemoryChannels, WithNBigCores, WithRV32, CacheBlockBytes} import freechips.rocketchip.diplomacy.{LazyModule, ValName} import freechips.rocketchip.devices.tilelink.BootROMParams -import freechips.rocketchip.tile.{RocketTileParams, MaxHartIdBits, XLen, BuildRoCC, TileKey, LazyRoCC} +import freechips.rocketchip.devices.debug.{Debug} +import freechips.rocketchip.tile.{XLen, BuildRoCC, TileKey, LazyRoCC, RocketTileParams, MaxHartIdBits} import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams, ICacheParams} +import freechips.rocketchip.util.{AsyncResetReg} import boom.common.{BoomTilesKey} @@ -33,23 +35,30 @@ import ConfigValName._ // Common Parameter Mixins // ----------------------- -/** - * Class to specify where the BootRom file is (from `rebar` top) - */ class WithBootROM extends Config((site, here, up) => { case BootROMParams => BootROMParams( contentFileName = s"./bootrom/bootrom.rv${site(XLen)}.img") }) -// DOC include start: WithGPIO -/** - * Class to add in GPIO - */ +// DOC include start: gpio mixin class WithGPIO extends Config((site, here, up) => { case PeripheryGPIOKey => Seq( GPIOParams(address = 0x10012000, width = 4, includeIOF = false)) + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) + // TODO: Currently FIRRTL will error if the GPIO input + // pins are unconnected, so tie them to 0. + // In future IO cell blackboxes will replace this with + // more correct functionality + for (gpio <- top.gpio) { + for (pin <- gpio.pins) { + pin.i.ival := false.B + } + } + top + } }) -// DOC include end: WithGPIO +// DOC include end: gpio mixin /** * Class to add in UART @@ -59,92 +68,58 @@ class WithUART extends Config((site, here, up) => { UARTParams(address = 0x54000000L, nTxEntries = 256, nRxEntries = 256)) }) -// ----------------------------------------------- -// BOOM and/or Rocket Top Level System Parameter Mixins -// ----------------------------------------------- -/** - * Class to specify a "plain" top level BOOM and/or Rocket system - */ -class WithTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - Module(LazyModule(new Top()(p)).module) +class WithNoGPIO extends Config((site, here, up) => { + case PeripheryGPIOKey => Seq() +}) + +// DOC include start: tsi mixin +class WithTSI extends Config((site, here, up) => { + case SerialKey => true + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) + success := top.connectSimSerial() + top + } +}) +// DOC include end: tsi mixin + +class WithDTM extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) + top.reset := reset.asBool | top.debug.map { debug => AsyncResetReg(debug.ndreset) }.getOrElse(false.B) + Debug.connectDebug(top.debug, top.psd, clock, reset.asBool, success)(p) + top } }) -/** - * Class to specify a top level BOOM and/or Rocket system with DTM - */ -class WithDTMTop extends Config((site, here, up) => { - case BuildTopWithDTM => (clock: Clock, reset: Bool, p: Parameters) => { - Module(LazyModule(new TopWithDTM()(p)).module) - } +// DOC include start: GCD mixin +class WithGCD(useAXI4: Boolean, useBlackBox: Boolean) extends Config((site, here, up) => { + case GCDKey => Some(GCDParams(useAXI4 = useAXI4, useBlackBox = useBlackBox)) }) +// DOC include end: GCD mixin -/** - * Class to specify a top level BOOM and/or Rocket system with PWM - */ -// DOC include start: WithPWMTop -class WithPWMTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new TopWithPWMTL()(p)).module) -}) -// DOC include end: WithPWMTop - -/** - * Class to specify a top level BOOM and/or Rocket system with a PWM AXI4 - */ -class WithPWMAXI4Top extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new TopWithPWMAXI4()(p)).module) -}) - -/** - * Class to specify a top level BOOM and/or Rocket system with a TL-attached GCD device - */ -class WithGCDTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new TopWithGCD()(p)).module) -}) - -/** - * Class to specify a top level BOOM and/or Rocket system with a block device - */ -class WithBlockDeviceModelTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new TopWithBlockDevice()(p)).module) +class WithBlockDeviceModel extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) top.connectBlockDeviceModel() top } }) -/** - * Class to specify a top level BOOM and/or Rocket system with a simulator block device - */ -class WithSimBlockDeviceTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new TopWithBlockDevice()(p)).module) +class WithSimBlockDevice extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) top.connectSimBlockDevice(clock, reset) top } }) -// DOC include start: WithGPIOTop -/** - * Class to specify a top level BOOM and/or Rocket system with GPIO - */ -class WithGPIOTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new TopWithGPIO()(p)).module) - for (gpio <- top.gpio) { - for (pin <- gpio.pins) { - pin.i.ival := false.B - } - } - top - } +// DOC include start: WithInitZero +class WithInitZero(base: BigInt, size: BigInt) extends Config((site, here, up) => { + case InitZeroKey => Some(InitZeroConfig(base, size)) }) -// DOC include end: WithGPIOTop +// DOC include end: WithInitZero // ------------------ // Multi-RoCC Support @@ -184,16 +159,6 @@ class WithMultiRoCCHwacha(harts: Int*) extends Config((site, here, up) => { } }) -// DOC include start: WithInitZero -class WithInitZero(base: BigInt, size: BigInt) extends Config((site, here, up) => { - case InitZeroKey => InitZeroConfig(base, size) -}) - -class WithInitZeroTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new TopWithInitZero()(p)).module) -}) -// DOC include end: WithInitZero /** * Mixin to add a small Rocket core to the system as a "control" core. @@ -227,15 +192,15 @@ class WithControlCore extends Config((site, here, up) => { class WithIceNIC(inBufFlits: Int = 1800, usePauser: Boolean = false) extends Config((site, here, up) => { - case NICKey => NICConfig( + case NICKey => Some(NICConfig( inBufFlits = inBufFlits, usePauser = usePauser, - checksumOffload = true) + checksumOffload = true)) }) -class WithLoopbackNICTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new TopWithIceNIC()(p)).module) +class WithLoopbackNIC extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) top.connectNicLoopback() top } diff --git a/generators/example/src/main/scala/GCD.scala b/generators/example/src/main/scala/GCD.scala new file mode 100644 index 00000000..f41e78db --- /dev/null +++ b/generators/example/src/main/scala/GCD.scala @@ -0,0 +1,200 @@ +package example + +import chisel3._ +import chisel3.util._ +import chisel3.experimental.{IntParam, BaseModule} +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.config.{Parameters, Field} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.regmapper.{HasRegMap, RegField} +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.UIntIsOneOf + +// DOC include start: GCD params +case class GCDParams( + address: BigInt = 0x2000, + width: Int = 32, + useAXI4: Boolean = false, + useBlackBox: Boolean = true) +// DOC include end: GCD params + +// DOC include start: GCD key +case object GCDKey extends Field[Option[GCDParams]](None) +// DOC include end: GCD key + +class GCDIO(val w: Int) extends Bundle { + val clock = Input(Clock()) + val reset = Input(Bool()) + val input_ready = Output(Bool()) + val input_valid = Input(Bool()) + val x = Input(UInt(w.W)) + val y = Input(UInt(w.W)) + val output_ready = Input(Bool()) + val output_valid = Output(Bool()) + val gcd = Output(UInt(w.W)) + val busy = Output(Bool()) +} + +trait GCDTopIO extends Bundle { + val gcd_busy = Output(Bool()) +} + +trait HasGCDIO extends BaseModule { + val w: Int + val io = IO(new GCDIO(w)) +} + +// DOC include start: GCD blackbox +class GCDMMIOBlackBox(val w: Int) extends BlackBox(Map("WIDTH" -> IntParam(w))) with HasBlackBoxResource + with HasGCDIO +{ + addResource("/vsrc/GCDMMIOBlackBox.v") +} +// DOC include end: GCD blackbox + +// DOC include start: GCD chisel +class GCDMMIOChiselModule(val w: Int) extends Module + with HasGCDIO +{ + val s_idle :: s_run :: s_done :: Nil = Enum(3) + + val state = RegInit(s_idle) + val tmp = Reg(UInt(w.W)) + val gcd = Reg(UInt(w.W)) + + io.input_ready := state === s_idle + io.output_valid := state === s_done + io.gcd := gcd + + when (state === s_idle && io.input_valid) { + state := s_run + } .elsewhen (state === s_run && tmp === 0.U) { + state := s_done + } .elsewhen (state === s_done && io.output_ready) { + state := s_idle + } + + when (state === s_idle && io.input_valid) { + gcd := io.x + tmp := io.y + } .elsewhen (state === s_run) { + when (gcd > tmp) { + gcd := gcd - tmp + } .otherwise { + tmp := tmp - gcd + } + } + + io.busy := state =/= s_idle +} +// DOC include end: GCD chisel + +// DOC include start: GCD instance regmap + +trait GCDModule extends HasRegMap { + val io: GCDTopIO + + implicit val p: Parameters + def params: GCDParams + val clock: Clock + val reset: Reset + + + // How many clock cycles in a PWM cycle? + val x = Reg(UInt(params.width.W)) + val y = Wire(new DecoupledIO(UInt(params.width.W))) + val gcd = Wire(new DecoupledIO(UInt(params.width.W))) + val status = Wire(UInt(2.W)) + + val impl = if (params.useBlackBox) { + Module(new GCDMMIOBlackBox(params.width)) + } else { + Module(new GCDMMIOChiselModule(params.width)) + } + + impl.io.clock := clock + impl.io.reset := reset.asBool + + impl.io.x := x + impl.io.y := y.bits + impl.io.input_valid := y.valid + y.ready := impl.io.input_ready + + gcd.bits := impl.io.gcd + gcd.valid := impl.io.output_valid + impl.io.output_ready := gcd.ready + + status := Cat(impl.io.input_ready, impl.io.output_ready) + io.gcd_busy := impl.io.busy + + regmap( + 0x00 -> Seq( + RegField.r(2, status)), // a read-only register capturing current status + 0x04 -> Seq( + RegField.w(params.width, x)), // a plain, write-only register + 0x08 -> Seq( + RegField.w(params.width, y)), // write-only, y.valid is set on write + 0x0C -> Seq( + RegField.r(params.width, gcd))) // read-only, gcd.ready is set on read +} +// DOC include end: GCD instance regmap + +// DOC include start: GCD router +class GCDTL(params: GCDParams, beatBytes: Int)(implicit p: Parameters) + extends TLRegisterRouter( + params.address, "gcd", Seq("ucbbar,gcd"), + beatBytes = beatBytes)( + new TLRegBundle(params, _) with GCDTopIO)( + new TLRegModule(params, _, _) with GCDModule) + +class GCDAXI4(params: GCDParams, beatBytes: Int)(implicit p: Parameters) + extends AXI4RegisterRouter( + params.address, + beatBytes=beatBytes)( + new AXI4RegBundle(params, _) with GCDTopIO)( + new AXI4RegModule(params, _, _) with GCDModule) +// DOC include end: GCD router + +// DOC include start: GCD lazy trait +trait CanHavePeripheryGCD { this: BaseSubsystem => + private val portName = "gcd" + + // Only build if we are using the TL (nonAXI4) version + val gcd = p(GCDKey) match { + case Some(params) => { + if (params.useAXI4) { + val gcd = LazyModule(new GCDAXI4(params, pbus.beatBytes)(p)) + pbus.toSlave(Some(portName)) { + gcd.node := + AXI4Buffer () := + TLToAXI4 () := + // toVariableWidthSlave doesn't use holdFirstDeny, which TLToAXI4() needsx + TLFragmenter(pbus.beatBytes, pbus.blockBytes, holdFirstDeny = true) + } + Some(gcd) + } else { + val gcd = LazyModule(new GCDTL(params, pbus.beatBytes)(p)) + pbus.toVariableWidthSlave(Some(portName)) { gcd.node } + Some(gcd) + } + } + case None => None + } +} +// DOC include end: GCD lazy trait + +// DOC include start: GCD imp trait +trait CanHavePeripheryGCDModuleImp extends LazyModuleImp { + val outer: CanHavePeripheryGCD + val gcd_busy = outer.gcd match { + case Some(gcd) => { + val busy = IO(Output(Bool())) + busy := gcd.module.io.gcd_busy + Some(busy) + } + case None => None + } +} + +// DOC include end: GCD imp trait diff --git a/generators/example/src/main/scala/GCDMMIOBlackBox.scala b/generators/example/src/main/scala/GCDMMIOBlackBox.scala deleted file mode 100644 index 891fe1c9..00000000 --- a/generators/example/src/main/scala/GCDMMIOBlackBox.scala +++ /dev/null @@ -1,98 +0,0 @@ -package example - -import chisel3._ -import chisel3.util._ -import chisel3.core.{IntParam, Reset} -import freechips.rocketchip.amba.axi4._ -import freechips.rocketchip.subsystem.BaseSubsystem -import freechips.rocketchip.config.{Parameters, Field} -import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.regmapper.{HasRegMap, RegField} -import freechips.rocketchip.tilelink._ -import freechips.rocketchip.util.UIntIsOneOf - -// DOC include start: GCD blackbox -class GCDMMIOBlackBox(w: Int) extends BlackBox(Map("WIDTH" -> IntParam(w))) with HasBlackBoxResource { - val io = IO(new Bundle { - val clock = Input(Clock()) - val reset = Input(Bool()) - val input_ready = Output(Bool()) - val input_valid = Input(Bool()) - val x = Input(UInt(w.W)) - val y = Input(UInt(w.W)) - val output_ready = Input(Bool()) - val output_valid = Output(Bool()) - val gcd = Output(UInt(w.W)) - }) - - addResource("/vsrc/GCDMMIOBlackBox.v") -} -// DOC include end: GCD blackbox - -// DOC include start: GCD instance regmap -case class GCDParams(address: BigInt, beatBytes: Int, width: Int) - -trait GCDModule extends HasRegMap { - implicit val p: Parameters - def params: GCDParams - val clock: Clock - val reset: Reset - - val impl = Module(new GCDMMIOBlackBox(params.width)) - - // How many clock cycles in a PWM cycle? - val x = Reg(UInt(params.width.W)) - val y = Wire(new DecoupledIO(impl.io.y)) - val gcd = Wire(new DecoupledIO(impl.io.gcd)) - val status = Cat(impl.io.input_ready, impl.io.output_valid) - - impl.io.clock := clock - impl.io.reset := reset.asBool - impl.io.x := x - impl.io.y := y.bits - impl.io.input_valid := y.valid - y.ready := impl.io.input_ready - - gcd.bits := impl.io.gcd - gcd.valid := impl.io.output_valid - impl.io.output_ready := gcd.ready - - regmap( - 0x00 -> Seq( - RegField.r(2, status)), // a read-only register capturing current status - 0x04 -> Seq( - RegField.w(params.width, x)), // a plain, write-only register - 0x08 -> Seq( - RegField.w(params.width, y)), // write-only, y.valid is set on write - 0x0C -> Seq( - RegField.r(params.width, gcd))) // read-only, gcd.ready is set on read -} -// DOC include end: GCD instance regmap - -// DOC include start: GCD cake -class GCD(c: GCDParams)(implicit p: Parameters) - extends TLRegisterRouter( - c.address, "gcd", Seq("ucbbar,gcd"), - beatBytes = c.beatBytes)( - new TLRegBundle(c, _))( - new TLRegModule(c, _, _) with GCDModule) - -trait HasPeripheryGCD { this: BaseSubsystem => - implicit val p: Parameters - - private val address = 0x2000 - private val portName = "gcd" - private val gcdWidth = 32 - - val gcd = LazyModule(new GCD( - GCDParams(address, pbus.beatBytes, gcdWidth))(p)) - - pbus.toVariableWidthSlave(Some(portName)) { gcd.node } -} - -trait HasPeripheryGCDModuleImp extends LazyModuleImp { - implicit val p: Parameters - val outer: HasPeripheryGCD -} - -// DOC include end: GCD cake diff --git a/generators/example/src/main/scala/HeteroConfigs.scala b/generators/example/src/main/scala/HeteroConfigs.scala index e5cebef9..d68532ad 100644 --- a/generators/example/src/main/scala/HeteroConfigs.scala +++ b/generators/example/src/main/scala/HeteroConfigs.scala @@ -9,10 +9,13 @@ import freechips.rocketchip.config.{Config} // --------------------- class LargeBoomAndRocketConfig extends Config( - new WithTop ++ // default top + new WithTSI ++ // use testchipip serial offchip link + new WithNoGPIO ++ // no top-level GPIO pins (overrides default set in sifive-blocks) new WithBootROM ++ // default bootrom new WithUART ++ // add a UART new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use SiFive l2 + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip) + new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip) new boom.common.WithRenumberHarts ++ // avoid hartid overlap new boom.common.WithLargeBooms ++ // 3-wide boom new boom.common.WithNBoomCores(1) ++ // single-core boom @@ -20,10 +23,13 @@ class LargeBoomAndRocketConfig extends Config( new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system class SmallBoomAndRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new boom.common.WithRenumberHarts ++ new boom.common.WithSmallBooms ++ // 1-wide boom new boom.common.WithNBoomCores(1) ++ @@ -32,11 +38,14 @@ class SmallBoomAndRocketConfig extends Config( // DOC include start: BoomAndRocketWithHwacha class HwachaLargeBoomAndHwachaRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new hwacha.DefaultHwachaConfig ++ // add hwacha to all harts new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ new boom.common.WithNBoomCores(1) ++ @@ -45,10 +54,13 @@ class HwachaLargeBoomAndHwachaRocketConfig extends Config( // DOC include end: BoomAndRocketWithHwacha class RoccLargeBoomAndRoccRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithRoccExample ++ // add example rocc accelerator to all harts + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ @@ -57,9 +69,12 @@ class RoccLargeBoomAndRoccRocketConfig extends Config( new freechips.rocketchip.system.BaseConfig) class DualLargeBoomAndRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ @@ -69,10 +84,13 @@ class DualLargeBoomAndRocketConfig extends Config( // DOC include start: DualBoomAndRocketOneHwacha class DualLargeBoomAndHwachaRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new WithMultiRoCC ++ // support heterogeneous rocc new WithMultiRoCCHwacha(2) ++ // put hwacha on hart-2 (rocket) new boom.common.WithRenumberHarts ++ @@ -83,10 +101,13 @@ class DualLargeBoomAndHwachaRocketConfig extends Config( // DOC include end: DualBoomAndRocketOneHwacha class LargeBoomAndRV32RocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ new boom.common.WithNBoomCores(1) ++ @@ -96,10 +117,13 @@ class LargeBoomAndRV32RocketConfig extends Config( // DOC include start: DualBoomAndRocket class DualLargeBoomAndDualRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ new boom.common.WithNBoomCores(2) ++ // 2 boom cores @@ -108,10 +132,13 @@ class DualLargeBoomAndDualRocketConfig extends Config( // DOC include end: DualBoomAndRocket class MultiCoreWithControlCoreConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new WithControlCore ++ // add small control core (last hartid) new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ diff --git a/generators/example/src/main/scala/InitZero.scala b/generators/example/src/main/scala/InitZero.scala index 3a90bfcc..4c7f3bbb 100644 --- a/generators/example/src/main/scala/InitZero.scala +++ b/generators/example/src/main/scala/InitZero.scala @@ -8,7 +8,7 @@ import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, IdRange} import testchipip.TLHelper case class InitZeroConfig(base: BigInt, size: BigInt) -case object InitZeroKey extends Field[InitZeroConfig] +case object InitZeroKey extends Field[Option[InitZeroConfig]](None) class InitZero(implicit p: Parameters) extends LazyModule { val node = TLHelper.makeClientNode( @@ -18,7 +18,7 @@ class InitZero(implicit p: Parameters) extends LazyModule { } class InitZeroModuleImp(outer: InitZero) extends LazyModuleImp(outer) { - val config = p(InitZeroKey) + val config = p(InitZeroKey).get val (mem, edge) = outer.node.out(0) val addrBits = edge.bundle.addressBits @@ -57,13 +57,11 @@ class InitZeroModuleImp(outer: InitZero) extends LazyModuleImp(outer) { } } -trait HasPeripheryInitZero { this: BaseSubsystem => +trait CanHavePeripheryInitZero { this: BaseSubsystem => implicit val p: Parameters - val initZero = LazyModule(new InitZero()(p)) - fbus.fromPort(Some("init-zero"))() := initZero.node -} - -trait HasPeripheryInitZeroModuleImp extends LazyModuleImp { - // Don't need anything here + p(InitZeroKey) .map { k => + val initZero = LazyModule(new InitZero()(p)) + fbus.fromPort(Some("init-zero"))() := initZero.node + } } diff --git a/generators/example/src/main/scala/PWM.scala b/generators/example/src/main/scala/PWM.scala deleted file mode 100644 index bd6056f4..00000000 --- a/generators/example/src/main/scala/PWM.scala +++ /dev/null @@ -1,134 +0,0 @@ -package example - -import chisel3._ -import chisel3.util._ -import freechips.rocketchip.amba.axi4._ -import freechips.rocketchip.subsystem.BaseSubsystem -import freechips.rocketchip.config.{Parameters, Field} -import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.regmapper.{HasRegMap, RegField} -import freechips.rocketchip.tilelink._ -import freechips.rocketchip.util.UIntIsOneOf - -// DOC include start: PWM generic traits -case class PWMParams(address: BigInt, beatBytes: Int) - -class PWMBase(w: Int) extends Module { - val io = IO(new Bundle { - val pwmout = Output(Bool()) - val period = Input(UInt(w.W)) - val duty = Input(UInt(w.W)) - val enable = Input(Bool()) - }) - - // The counter should count up until period is reached - val counter = Reg(UInt(w.W)) - - when (counter >= (io.period - 1.U)) { - counter := 0.U - } .otherwise { - counter := counter + 1.U - } - - // If PWM is enabled, pwmout is high when counter < duty - // If PWM is not enabled, it will always be low - io.pwmout := io.enable && (counter < io.duty) -} - -trait PWMBundle extends Bundle { - val pwmout = Output(Bool()) -} - -trait PWMModule extends HasRegMap { - val io: PWMBundle - implicit val p: Parameters - def params: PWMParams - - // How many clock cycles in a PWM cycle? - val period = Reg(UInt(32.W)) - // For how many cycles should the clock be high? - val duty = Reg(UInt(32.W)) - // Is the PWM even running at all? - val enable = RegInit(false.B) - - val base = Module(new PWMBase(32)) - io.pwmout := base.io.pwmout - base.io.period := period - base.io.duty := duty - base.io.enable := enable - - regmap( - 0x00 -> Seq( - RegField(32, period)), - 0x04 -> Seq( - RegField(32, duty)), - 0x08 -> Seq( - RegField(1, enable))) -} -// DOC include end: PWM generic traits - -// DOC include start: PWMTL -class PWMTL(c: PWMParams)(implicit p: Parameters) - extends TLRegisterRouter( - c.address, "pwm", Seq("ucbbar,pwm"), - beatBytes = c.beatBytes)( - new TLRegBundle(c, _) with PWMBundle)( - new TLRegModule(c, _, _) with PWMModule) -// DOC include end: PWMTL - -class PWMAXI4(c: PWMParams)(implicit p: Parameters) - extends AXI4RegisterRouter(c.address, beatBytes = c.beatBytes)( - new AXI4RegBundle(c, _) with PWMBundle)( - new AXI4RegModule(c, _, _) with PWMModule) - -// DOC include start: HasPeripheryPWMTL -trait HasPeripheryPWMTL { this: BaseSubsystem => - implicit val p: Parameters - - private val address = 0x2000 - private val portName = "pwm" - - val pwm = LazyModule(new PWMTL( - PWMParams(address, pbus.beatBytes))(p)) - - pbus.toVariableWidthSlave(Some(portName)) { pwm.node } -} -// DOC include end: HasPeripheryPWMTL - -// DOC include start: HasPeripheryPWMTLModuleImp -trait HasPeripheryPWMTLModuleImp extends LazyModuleImp { - implicit val p: Parameters - val outer: HasPeripheryPWMTL - - val pwmout = IO(Output(Bool())) - - pwmout := outer.pwm.module.io.pwmout -} -// DOC include end: HasPeripheryPWMTLModuleImp - -trait HasPeripheryPWMAXI4 { this: BaseSubsystem => - implicit val p: Parameters - - private val address = 0x2000 - private val portName = "pwm" - - val pwm = LazyModule(new PWMAXI4( - PWMParams(address, pbus.beatBytes))(p)) - - pbus.toSlave(Some(portName)) { - pwm.node := - AXI4Buffer () := - TLToAXI4() := - // toVariableWidthSlave doesn't use holdFirstDeny, which TLToAXI4() needs - TLFragmenter(pbus.beatBytes, pbus.blockBytes, holdFirstDeny = true) - } -} - -trait HasPeripheryPWMAXI4ModuleImp extends LazyModuleImp { - implicit val p: Parameters - val outer: HasPeripheryPWMAXI4 - - val pwmout = IO(Output(Bool())) - - pwmout := outer.pwm.module.io.pwmout -} diff --git a/generators/example/src/main/scala/RocketConfigs.scala b/generators/example/src/main/scala/RocketConfigs.scala index edd18a36..4ccc2fd4 100644 --- a/generators/example/src/main/scala/RocketConfigs.scala +++ b/generators/example/src/main/scala/RocketConfigs.scala @@ -9,17 +9,23 @@ import freechips.rocketchip.config.{Config} // -------------- class RocketConfig extends Config( - new WithTop ++ // use default top + new WithTSI ++ // use testchipip serial offchip link + new WithNoGPIO ++ // no top-level GPIO pins (overrides default set in sifive-blocks) new WithBootROM ++ // use default bootrom new WithUART ++ // add a UART + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip) + new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip) new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system class HwachaRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -27,9 +33,12 @@ class HwachaRocketConfig extends Config( // DOC include start: GemminiRocketConfig class GemminiRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new gemmini.DefaultGemminiConfig ++ // use Gemmini systolic array GEMM accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -37,9 +46,12 @@ class GemminiRocketConfig extends Config( // DOC include end: GemminiRocketConfig class RoccRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithRoccExample ++ // use example RoCC-based accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -47,10 +59,13 @@ class RoccRocketConfig extends Config( // DOC include start: JtagRocket class jtagRocketConfig extends Config( - new WithDTMTop ++ // use top with dtm - new freechips.rocketchip.subsystem.WithJtagDTM ++ // add jtag+DTM module to coreplex + new WithDTM ++ // use top with dtm + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithJtagDTM ++ // enable communicating with the DTM using jtag + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -58,100 +73,127 @@ class jtagRocketConfig extends Config( // DOC include start: DmiRocket class dmiRocketConfig extends Config( - new WithDTMTop ++ // use top with dtm + new WithDTM ++ // use top with dtm + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include end: DmiRocket -// DOC include start: PWMRocketConfig -class PWMRocketConfig extends Config( - new WithPWMTop ++ // use top with tilelink-controlled PWM - new WithBootROM ++ +// DOC include start: GCDTLRocketConfig +class GCDTLRocketConfig extends Config( + new WithTSI ++ + new WithNoGPIO ++ new WithUART ++ + new WithGCD(useAXI4=false, useBlackBox=false) ++ // Use GCD Chisel, connect Tilelink + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) -// DOC include end: PWMRocketConfig +// DOC include end: GCDTLRocketConfig -class PWMAXI4RocketConfig extends Config( - new WithPWMAXI4Top ++ // use top with axi4-controlled PWM - new WithBootROM ++ - new WithUART ++ - new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.system.BaseConfig) - -class GCDRocketConfig extends Config( // add MMIO GCD module - new WithGCDTop ++ - new WithBootROM ++ +// DOC include start: GCDAXI4BlackBoxRocketConfig +class GCDAXI4BlackBoxRocketConfig extends Config( + new WithTSI ++ new WithUART ++ + new WithNoGPIO ++ + new WithGCD(useAXI4=true, useBlackBox=true) ++ // Use GCD blackboxed verilog, connect by AXI4->Tilelink + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) +// DOC include end: GCDAXI4BlackBoxRocketConfig class SimBlockDeviceRocketConfig extends Config( + new WithTSI ++ + new WithNoGPIO ++ new testchipip.WithBlockDevice ++ // add block-device module to peripherybus - new WithSimBlockDeviceTop ++ // use top with block-device IOs and connect to simblockdevice + new WithSimBlockDevice ++ // use top with block-device IOs and connect to simblockdevice new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) class BlockDeviceModelRocketConfig extends Config( + new WithTSI ++ + new WithNoGPIO ++ new testchipip.WithBlockDevice ++ // add block-device module to periphery bus - new WithBlockDeviceModelTop ++ // use top with block-device IOs and connect to a blockdevicemodel + new WithBlockDeviceModel ++ // use top with block-device IOs and connect to a blockdevicemodel new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include start: GPIORocketConfig class GPIORocketConfig extends Config( + new WithTSI ++ new WithGPIO ++ // add GPIOs to the peripherybus - new WithGPIOTop ++ // use top with GPIOs new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include end: GPIORocketConfig class DualCoreRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ new WithBootROM ++ new WithUART ++ + new WithNoGPIO ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(2) ++ // dual-core (2 RocketTiles) new freechips.rocketchip.system.BaseConfig) class RV32RocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithRV32 ++ // set RocketTiles to be 32-bit new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) class GB1MemoryRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithExtMemSize((1<<30) * 1L) ++ // use 2GB simulated external memory + new freechips.rocketchip.subsystem.WithExtMemSize((1<<30) * 1L) ++ // use 1GB simulated external memory new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include start: Sha3Rocket class Sha3RocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new sha3.WithSha3Accel ++ // add SHA3 rocc accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -160,20 +202,27 @@ class Sha3RocketConfig extends Config( // DOC include start: InitZeroRocketConfig class InitZeroRocketConfig extends Config( - new WithInitZero(0x88000000L, 0x1000L) ++ - new WithInitZeroTop ++ + new WithInitZero(0x88000000L, 0x1000L) ++ // add InitZero + new WithNoGPIO ++ + new WithTSI ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include end: InitZeroRocketConfig class LoopbackNICRocketConfig extends Config( + new WithTSI ++ new WithIceNIC ++ - new WithLoopbackNICTop ++ + new WithNoGPIO ++ + new WithLoopbackNIC ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) diff --git a/generators/example/src/main/scala/TestHarness.scala b/generators/example/src/main/scala/TestHarness.scala index 3eaa05e2..50c872f2 100644 --- a/generators/example/src/main/scala/TestHarness.scala +++ b/generators/example/src/main/scala/TestHarness.scala @@ -10,12 +10,22 @@ import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.util.GeneratorApp import freechips.rocketchip.devices.debug.{Debug} +/** + * TODO: Why do we need this? + */ +import ConfigValName._ + // ------------------------------- // BOOM and/or Rocket Test Harness // ------------------------------- -case object BuildTop extends Field[(Clock, Bool, Parameters) => TopModule[Top]] -case object BuildTopWithDTM extends Field[(Clock, Bool, Parameters) => TopWithDTMModule[TopWithDTM]] +case object BuildTop extends Field[(Clock, Bool, Parameters, Bool) => TopModule[Top]]( + (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = Module(LazyModule(new Top()(p)).suggestName("top").module) + top.debug.map { debug => debug := DontCare } + top + } +) /** * Test harness using TSI to bringup the system @@ -25,48 +35,8 @@ class TestHarness(implicit val p: Parameters) extends Module { val success = Output(Bool()) }) - // force Chisel to rename module - override def desiredName = "TestHarness" - - val dut = p(BuildTop)(clock, reset.toBool, p) - - dut.debug.foreach(_ := DontCare) - dut.connectSimAXIMem() - dut.connectSimAXIMMIO() - dut.dontTouchPorts() - dut.tieOffInterrupts() - dut.l2_frontend_bus_axi4.foreach(axi => { - axi.tieoff() - experimental.DataMirror.directionOf(axi.ar.ready) match { - case core.ActualDirection.Input => - axi.r.bits := DontCare - axi.b.bits := DontCare - case core.ActualDirection.Output => - axi.aw.bits := DontCare - axi.ar.bits := DontCare - axi.w.bits := DontCare - } - }) + val dut = p(BuildTop)(clock, reset.toBool, p, io.success) dut.connectSimUARTs() - - io.success := dut.connectSimSerial() -} - -/** - * Test harness using the Debug Test Module (DTM) to bringup the system - */ -class TestHarnessWithDTM(implicit p: Parameters) extends Module -{ - val io = IO(new Bundle { - val success = Output(Bool()) - }) - - // force Chisel to rename module - override def desiredName = "TestHarness" - - val dut = p(BuildTopWithDTM)(clock, reset.toBool, p) - - dut.reset := reset.asBool | dut.debug.get.ndreset dut.connectSimAXIMem() dut.connectSimAXIMMIO() dut.dontTouchPorts() @@ -84,5 +54,4 @@ class TestHarnessWithDTM(implicit p: Parameters) extends Module } }) - Debug.connectDebug(dut.debug, dut.psd, clock, reset.asBool, io.success) } diff --git a/generators/example/src/main/scala/Top.scala b/generators/example/src/main/scala/Top.scala index defb4ef4..cd222379 100644 --- a/generators/example/src/main/scala/Top.scala +++ b/generators/example/src/main/scala/Top.scala @@ -15,103 +15,33 @@ import utilities.{System, SystemModule} import sifive.blocks.devices.gpio._ import sifive.blocks.devices.uart._ -import icenet.{HasPeripheryIceNIC, HasPeripheryIceNICModuleImp} +import icenet.{CanHavePeripheryIceNIC, CanHavePeripheryIceNICModuleImp} // ------------------------------------ // BOOM and/or Rocket Top Level Systems // ------------------------------------ +// DOC include start: Top class Top(implicit p: Parameters) extends System - with HasNoDebug - with HasPeripherySerial - with CanHavePeripheryUARTWithAdapter { + with CanHavePeripheryUARTAdapter // Enables optionally adding the UART print adapter + with HasPeripheryUART // Enables optionally adding the sifive UART + with HasPeripheryGPIO // Enables optionally adding the sifive GPIOs + with CanHavePeripheryBlockDevice // Enables optionally adding the block device + with CanHavePeripheryInitZero // Enables optionally adding the initzero example widget + with CanHavePeripheryGCD // Enables optionally adding the GCD example widget + with CanHavePeripherySerial // Enables optionally adding the TSI serial-adapter and port + with CanHavePeripheryIceNIC // Enables optionally adding the IceNIC for firesim +{ override lazy val module = new TopModule(this) } class TopModule[+L <: Top](l: L) extends SystemModule(l) - with HasNoDebugModuleImp - with HasPeripherySerialModuleImp - with CanHavePeripheryUARTWithAdapterImp - with DontTouch - -//--------------------------------------------------------------------------------------------------------- -// DOC include start: TopWithPWMTL - -class TopWithPWMTL(implicit p: Parameters) extends Top - with HasPeripheryPWMTL { - override lazy val module = new TopWithPWMTLModule(this) -} - -class TopWithPWMTLModule(l: TopWithPWMTL) extends TopModule(l) - with HasPeripheryPWMTLModuleImp - -// DOC include end: TopWithPWMTL -//--------------------------------------------------------------------------------------------------------- - -class TopWithPWMAXI4(implicit p: Parameters) extends Top - with HasPeripheryPWMAXI4 { - override lazy val module = new TopWithPWMAXI4Module(this) -} - -class TopWithPWMAXI4Module(l: TopWithPWMAXI4) extends TopModule(l) - with HasPeripheryPWMAXI4ModuleImp - -//--------------------------------------------------------------------------------------------------------- - -class TopWithGCD(implicit p: Parameters) extends Top - with HasPeripheryGCD { - override lazy val module = new TopWithGCDModule(this) -} - -class TopWithGCDModule(l: TopWithGCD) extends TopModule(l) - with HasPeripheryGCDModuleImp - -//--------------------------------------------------------------------------------------------------------- - -class TopWithBlockDevice(implicit p: Parameters) extends Top - with HasPeripheryBlockDevice { - override lazy val module = new TopWithBlockDeviceModule(this) -} - -class TopWithBlockDeviceModule(l: TopWithBlockDevice) extends TopModule(l) - with HasPeripheryBlockDeviceModuleImp - -//--------------------------------------------------------------------------------------------------------- - -class TopWithGPIO(implicit p: Parameters) extends Top - with HasPeripheryGPIO { - override lazy val module = new TopWithGPIOModule(this) -} - -class TopWithGPIOModule(l: TopWithGPIO) - extends TopModule(l) with HasPeripheryGPIOModuleImp - -//--------------------------------------------------------------------------------------------------------- - -class TopWithDTM(implicit p: Parameters) extends System -{ - override lazy val module = new TopWithDTMModule(this) -} - -class TopWithDTMModule[+L <: TopWithDTM](l: L) extends SystemModule(l) - -//--------------------------------------------------------------------------------------------------------- -// DOC include start: TopWithInitZero -class TopWithInitZero(implicit p: Parameters) extends Top - with HasPeripheryInitZero { - override lazy val module = new TopWithInitZeroModuleImp(this) -} - -class TopWithInitZeroModuleImp(l: TopWithInitZero) extends TopModule(l) - with HasPeripheryInitZeroModuleImp -// DOC include end: TopWithInitZero - -class TopWithIceNIC(implicit p: Parameters) extends Top - with HasPeripheryIceNIC { - override lazy val module = new TopWithIceNICModule(this) -} - -class TopWithIceNICModule(outer: TopWithIceNIC) - extends TopModule(outer) - with HasPeripheryIceNICModuleImp + with HasPeripheryUARTModuleImp + with CanHavePeripheryBlockDeviceModuleImp + with CanHavePeripheryGCDModuleImp + with CanHavePeripherySerialModuleImp + with CanHavePeripheryIceNICModuleImp + with CanHavePeripheryUARTAdapterModuleImp + with DontTouch +// DOC include end: Top diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index c3a6ca80..f0c9c664 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -10,7 +10,7 @@ import freechips.rocketchip.devices.debug.HasPeripheryDebugModuleImp import freechips.rocketchip.subsystem.{CanHaveMasterAXI4MemPortModuleImp} import sifive.blocks.devices.uart.HasPeripheryUARTModuleImp -import testchipip.{HasPeripherySerialModuleImp, HasPeripheryBlockDeviceModuleImp} +import testchipip.{CanHavePeripherySerialModuleImp, CanHavePeripheryBlockDeviceModuleImp} import icenet.HasPeripheryIceNICModuleImpValidOnly import junctions.{NastiKey, NastiParameters} @@ -32,19 +32,19 @@ class WithTiedOffDebug extends RegisterBridgeBinder({ case target: HasPeripheryD }) class WithSerialBridge extends RegisterBridgeBinder({ - case target: HasPeripherySerialModuleImp => Seq(SerialBridge(target.serial)(target.p)) + case target: CanHavePeripherySerialModuleImp => Seq(SerialBridge(target.serial.get)(target.p)) }) class WithNICBridge extends RegisterBridgeBinder({ - case target: HasPeripheryIceNICModuleImpValidOnly => Seq(NICBridge(target.net)(target.p)) + case target: HasPeripheryIceNICModuleImpValidOnly => Seq(NICBridge(target.net)(target.p)) }) class WithUARTBridge extends RegisterBridgeBinder({ - case target: HasPeripheryUARTModuleImp => target.uart.map(u => UARTBridge(u)(target.p)) + case target: HasPeripheryUARTModuleImp => target.uart.map(u => UARTBridge(u)(target.p)) }) class WithBlockDeviceBridge extends RegisterBridgeBinder({ - case target: HasPeripheryBlockDeviceModuleImp => Seq(BlockDevBridge(target.bdev, target.reset.toBool)(target.p)) + case target: CanHavePeripheryBlockDeviceModuleImp => Seq(BlockDevBridge(target.bdev.get, target.reset.toBool)(target.p)) }) class WithFASEDBridge extends RegisterBridgeBinder({ diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 4cb0b990..17ac06e6 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -12,7 +12,7 @@ import freechips.rocketchip.subsystem._ import freechips.rocketchip.devices.tilelink.BootROMParams import freechips.rocketchip.devices.debug.{DebugModuleParams, DebugModuleKey} import boom.common.BoomTilesKey -import testchipip.{BlockDeviceKey, BlockDeviceConfig} +import testchipip.{BlockDeviceKey, BlockDeviceConfig, SerialKey} import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} import scala.math.{min, max} import tracegen.TraceGenKey @@ -47,13 +47,17 @@ class WithUARTKey extends Config((site, here, up) => { nRxEntries = 256)) }) +class WithSerial extends Config((site, here, up) => { + case SerialKey => true +}) + class WithBlockDevice extends Config(new testchipip.WithBlockDevice) class WithNICKey extends Config((site, here, up) => { - case NICKey => NICConfig( + case NICKey => Some(NICConfig( inBufFlits = 8192, ctrlQueueDepth = 64, - checksumOffload = true) + checksumOffload = true)) }) class WithRocketL2TLBs(entries: Int) extends Config((site, here, up) => { @@ -112,6 +116,7 @@ class FireSimRocketChipConfig extends Config( new WithoutTLMonitors ++ new WithUARTKey ++ new WithNICKey ++ + new WithSerial ++ new WithBlockDevice ++ new WithRocketL2TLBs(1024) ++ new WithPerfCounters ++ @@ -169,6 +174,7 @@ class FireSimBoomConfig extends Config( new WithoutTLMonitors ++ new WithUARTKey ++ new WithNICKey ++ + new WithSerial ++ new WithBlockDevice ++ new WithBoomL2TLBs(1024) ++ new WithoutClockGating ++ diff --git a/generators/firechip/src/main/scala/Targets.scala b/generators/firechip/src/main/scala/Targets.scala index 4c790195..b608e67b 100644 --- a/generators/firechip/src/main/scala/Targets.scala +++ b/generators/firechip/src/main/scala/Targets.scala @@ -42,10 +42,10 @@ class FireSimDUT(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology with CanHaveMasterAXI4MemPort with HasPeripheryBootROM - with HasPeripherySerial + with CanHavePeripherySerial with HasPeripheryUART - with HasPeripheryIceNIC - with HasPeripheryBlockDevice + with CanHavePeripheryIceNIC + with CanHavePeripheryBlockDevice with HasTraceIO { override lazy val module = new FireSimModuleImp(this) @@ -55,10 +55,10 @@ class FireSimModuleImp[+L <: FireSimDUT](l: L) extends SubsystemModuleImp(l) with HasRTCModuleImp with CanHaveMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp - with HasPeripherySerialModuleImp + with CanHavePeripherySerialModuleImp with HasPeripheryUARTModuleImp with HasPeripheryIceNICModuleImpValidOnly - with HasPeripheryBlockDeviceModuleImp + with CanHavePeripheryBlockDeviceModuleImp with HasTraceIOImp with CanHaveMultiCycleRegfileImp @@ -68,9 +68,9 @@ class FireSimNoNICDUT(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology with CanHaveMasterAXI4MemPort with HasPeripheryBootROM - with HasPeripherySerial + with CanHavePeripherySerial with HasPeripheryUART - with HasPeripheryBlockDevice + with CanHavePeripheryBlockDevice with HasTraceIO { override lazy val module = new FireSimNoNICModuleImp(this) @@ -80,9 +80,9 @@ class FireSimNoNICModuleImp[+L <: FireSimNoNICDUT](l: L) extends SubsystemModule with HasRTCModuleImp with CanHaveMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp - with HasPeripherySerialModuleImp + with CanHavePeripherySerialModuleImp with HasPeripheryUARTModuleImp - with HasPeripheryBlockDeviceModuleImp + with CanHavePeripheryBlockDeviceModuleImp with HasTraceIOImp with CanHaveMultiCycleRegfileImp @@ -107,12 +107,11 @@ class FireSimSupernode(implicit p: Parameters) extends DefaultFireSimHarness(() // Verilog blackbox integration demo class FireSimVerilogGCDDUT(implicit p: Parameters) extends FireSimDUT - with example.HasPeripheryGCD + with example.CanHavePeripheryGCD { override lazy val module = new FireSimVerilogGCDModuleImp(this) } class FireSimVerilogGCDModuleImp[+L <: FireSimVerilogGCDDUT](l: L) extends FireSimModuleImp(l) - with example.HasPeripheryGCDModuleImp class FireSimVerilogGCD(implicit p: Parameters) extends DefaultFireSimHarness(() => new FireSimVerilogGCDDUT) diff --git a/generators/icenet b/generators/icenet index 87b3bf5e..2874db7f 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit 87b3bf5e46da3db6f9a653fdd6786699c075bff3 +Subproject commit 2874db7fdc5bee81074bdfe9cbbd4f68a9881943 diff --git a/generators/sha3 b/generators/sha3 index 6814c999..faf08c0f 160000 --- a/generators/sha3 +++ b/generators/sha3 @@ -1 +1 @@ -Subproject commit 6814c9991336c5092e7ce7c06f7a8e8bc4283958 +Subproject commit faf08c0f39593b1005398830cc825bec43c0a610 diff --git a/generators/testchipip b/generators/testchipip index db01ac15..62cf2629 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit db01ac1514d68fe55af2eb8f5bffb52da596ed75 +Subproject commit 62cf2629a7f2df054224c7dfbb9ff84b9e2b1203 diff --git a/sims/firesim b/sims/firesim index d799550b..5f6bd4fa 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit d799550b42c4bf0a1030cf93dde3a27263bfcc95 +Subproject commit 5f6bd4fa16af5d2fc15c49b54358f57dbd2c1469