From 1f98c842100f4fa1e4b39cc0fc95e7b5f19a8829 Mon Sep 17 00:00:00 2001 From: John Wright Date: Wed, 1 Apr 2020 14:03:56 -0700 Subject: [PATCH] Add ChipTop to enable real chip configs with IO cells, etc. (#480) This adds an additional layer (ChipTop) between the System module and the TestHarness. The IOBinder API is now changed to take only a single parameter (an Any) and return a 3 things: The IO port(s), the IO cell(s), and a function to call inside the test harness, which is analogous to the old IOBinder function, except that it takes a TestHarness object as an argument instead of (clock, reset, success). * A new Top-level module, ChipTop, has been created. ChipTop instantiates a "system" module specified by BuildSystem. * BuildTop now builds a ChipTop dut module in the TestHarness by default * A new BuildSystem key has been added, which by default builds DigitalTop (previously just called Top) * The IOBinders API has changed. IOBinders are now called inside of ChipTop and return a tuple3 of (IO ports, IO cells, harness functions). The harness functions are now called inside the TestHarness (this is analogous to the previous IOBinder functions). * IO cell models have been included in ChipTop. These can be replaced with real IO cells for tapeout, or used as-is for simulation. * The default for the TOP make variable is now ChipTop (was Top) --- build.sbt | 6 +- common.mk | 2 +- docs/Advanced-Concepts/Top-Testharness.rst | 21 +- .../Configs-Parameters-Mixins.rst | 15 +- docs/Customization/DMA-Devices.rst | 6 +- docs/Customization/IOBinders.rst | 24 +- docs/Customization/Keys-Traits-Configs.rst | 16 +- docs/Customization/MMIO-Peripherals.rst | 18 +- .../chipyard/src/main/scala/ChipTop.scala | 102 ++++++++ .../src/main/scala/ConfigFragments.scala | 16 +- .../scala/{Top.scala => DigitalTop.scala} | 10 +- .../chipyard/src/main/scala/IOBinders.scala | 237 +++++++++++++----- .../chipyard/src/main/scala/TestHarness.scala | 28 ++- .../main/scala/config/TracegenConfigs.scala | 10 +- .../src/main/scala/BridgeBinders.scala | 70 ++++-- .../firechip/src/main/scala/FireSim.scala | 6 +- .../src/main/scala/FireSimMulticlockPOC.scala | 12 +- .../src/main/scala/TargetConfigs.scala | 1 - generators/icenet | 2 +- generators/testchipip | 2 +- scripts/tutorial-patches/build.sbt.patch | 2 +- tools/barstools | 2 +- variables.mk | 2 +- 23 files changed, 444 insertions(+), 166 deletions(-) create mode 100644 generators/chipyard/src/main/scala/ChipTop.scala rename generators/chipyard/src/main/scala/{Top.scala => DigitalTop.scala} (86%) diff --git a/build.sbt b/build.sbt index b0eea0a8..05f05d7b 100644 --- a/build.sbt +++ b/build.sbt @@ -122,8 +122,12 @@ lazy val testchipip = (project in file("generators/testchipip")) .dependsOn(rocketchip, sifive_blocks) .settings(commonSettings) +lazy val iocell = (project in file("./tools/barstools/iocell/")) + .dependsOn(chisel) + .settings(commonSettings) + lazy val chipyard = conditionalDependsOn(project in file("generators/chipyard")) - .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities, + .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities, iocell, sha3, // On separate line to allow for cleaner tutorial-setup patches gemmini, icenet, tracegen, ariane) .settings(commonSettings) diff --git a/common.mk b/common.mk index 4fb2cf82..a98e0e24 100644 --- a/common.mk +++ b/common.mk @@ -20,7 +20,7 @@ include $(base_dir)/generators/tracegen/tracegen.mk ######################################################################################### lookup_srcs = $(shell find -L $(1)/ -name target -prune -o -iname "*.$(2)" -print 2> /dev/null) -SOURCE_DIRS = $(addprefix $(base_dir)/,generators sims/firesim/sim) +SOURCE_DIRS = $(addprefix $(base_dir)/,generators sims/firesim/sim tools/barstools/iocell) SCALA_SOURCES = $(call lookup_srcs,$(SOURCE_DIRS),scala) VLOG_SOURCES = $(call lookup_srcs,$(SOURCE_DIRS),sv) $(call lookup_srcs,$(SOURCE_DIRS),v) diff --git a/docs/Advanced-Concepts/Top-Testharness.rst b/docs/Advanced-Concepts/Top-Testharness.rst index 8df37769..ebd5b370 100644 --- a/docs/Advanced-Concepts/Top-Testharness.rst +++ b/docs/Advanced-Concepts/Top-Testharness.rst @@ -2,17 +2,28 @@ Tops, Test-Harnesses, and the Test-Driver =========================================== The three highest levels of hierarchy in a Chipyard -SoC are the Top (DUT), ``TestHarness``, and the ``TestDriver``. -The Top and ``TestHarness`` are both emitted by Chisel generators. +SoC are the ``ChipTop`` (DUT), ``TestHarness``, and the ``TestDriver``. +The ``ChipTop`` and ``TestHarness`` are both emitted by Chisel generators. The ``TestDriver`` serves as our testbench, and is a Verilog file in Rocket Chip. -Top/DUT +ChipTop/DUT ------------------------- -The top-level module of a Rocket Chip SoC is composed via cake-pattern. -Specifically, "Tops" extend a ``System``, which extends a ``Subsystem``, which extends a ``BaseSubsystem``. +``ChipTop`` is the top-level module that instantiates the ``System`` submodule, usually an instance of the concrete class ``DigitalTop``. +The vast majority of the design resides in the ``System``. +Other components that exist inside the ``ChipTop`` layer are generally IO cells, clock receivers and multiplexers, reset synchronizers, and other analog IP that needs to exist outside of the ``System``. +The ``IOBinders`` are responsible for instantiating the IO cells and defining the test harness collateral that connects to the top-level ports. +Most of these types of devices can be instantiated using custom ``IOBinders``, so the provided ``ChipTop`` and ``ChipTopCaughtReset`` classes are sufficient. +However, if needed, the ``BaseChipTop`` abstract class can be extended for building more custom ``ChipTop`` designs. + + +System/DigitalTop +------------------------- + +The system module of a Rocket Chip SoC is composed via cake-pattern. +Specifically, ``DigitalTop`` extends a ``System``, which extends a ``Subsystem``, which extends a ``BaseSubsystem``. BaseSubsystem diff --git a/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst b/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst index 9d7d86d0..94067aa1 100644 --- a/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst +++ b/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst @@ -77,10 +77,10 @@ It is used in the Rocket Chip SoC library and Chipyard framework in merging mult This example shows the Chipyard default top that composes multiple traits together into a fully-featured SoC with many optional components. -.. literalinclude:: ../../generators/chipyard/src/main/scala/Top.scala +.. literalinclude:: ../../generators/chipyard/src/main/scala/DigitalTop.scala :language: scala - :start-after: DOC include start: Top - :end-before: DOC include end: Top + :start-after: DOC include start: DigitalTop + :end-before: DOC include end: DigitalTop There are two "cakes" or mixins here. One for the lazy module (ex. ``CanHavePeripherySerial``) and one for the lazy module @@ -88,8 +88,8 @@ implementation (ex. ``CanHavePeripherySerialModuleImp`` where ``Imp`` refers to all the logical connections between generators and exchanges configuration information among them, while the lazy module implementation performs the actual Chisel RTL elaboration. -In the ``Top`` example class, the "outer" ``Top`` instantiates the "inner" -``TopModule`` as a lazy module implementation. This delays immediate elaboration +In the ``DigitalTop`` example class, the "outer" ``DigitalTop`` instantiates the "inner" +``DigitalTopModule`` as a lazy module implementation. This delays immediate elaboration of the module until all logical connections are determined and all configuration information is exchanged. The ``System`` outer base class, as well as the ``CanHavePeriphery`` outer traits contain code to perform high-level logical @@ -102,8 +102,9 @@ For example, the ``CanHavePeripherySerialModuleImp`` trait optionally physically the ``SerialAdapter`` module, and instantiates queues. In the test harness, the SoC is elaborated with -``val dut = Module(LazyModule(Top))``. -After elaboration, the result will be a ``Top`` module, which contains a +``val dut = p(BuildTop)(p)``. + +After elaboration, the system submodule of ``ChipTop`` will be a ``DigitalTop`` module, which contains a ``SerialAdapter`` module (among others), if the config specified for that block to be instantiated. From a high level, classes which extend ``LazyModule`` *must* reference diff --git a/docs/Customization/DMA-Devices.rst b/docs/Customization/DMA-Devices.rst index 554ff2d4..549a1556 100644 --- a/docs/Customization/DMA-Devices.rst +++ b/docs/Customization/DMA-Devices.rst @@ -15,10 +15,10 @@ that writes zeros to the memory at a configured address. .. literalinclude:: ../../generators/chipyard/src/main/scala/example/InitZero.scala :language: scala -.. literalinclude:: ../../generators/chipyard/src/main/scala/Top.scala +.. literalinclude:: ../../generators/chipyard/src/main/scala/DigitalTop.scala :language: scala - :start-after: DOC include start: Top - :end-before: DOC include end: Top + :start-after: DOC include start: DigitalTop + :end-before: DOC include end: DigitalTop 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). diff --git a/docs/Customization/IOBinders.rst b/docs/Customization/IOBinders.rst index 59924a0f..6332d07a 100644 --- a/docs/Customization/IOBinders.rst +++ b/docs/Customization/IOBinders.rst @@ -1,7 +1,7 @@ IOBinders ========= -In Chipyard we use a special ``Parameters`` key, ``IOBinders`` to determine what modules to bind to the IOs of a ``Top`` in the ``TestHarness``. +In Chipyard we use a special ``Parameters`` key, ``IOBinders`` to instantiate IO cells in the ``ChipTop`` layer and determine what modules to bind to the IOs of a ``ChipTop`` in the ``TestHarness``. .. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala :language: scala @@ -9,11 +9,27 @@ In Chipyard we use a special ``Parameters`` key, ``IOBinders`` to determine what :end-before: DOC include end: IOBinders -This special key solves the problem of duplicating test-harnesses for each different ``Top`` type. +This special key solves the problem of duplicating test-harnesses for each different ``System`` type. +You could just as well create a custom harness module that attaches IOs explicitly. +Instead, the ``IOBinders`` key provides a map from Scala traits to attachment behaviors. +Each ``IOBinder`` returns a tuple of three values: the list of ``ChipTop`` ports created by the ``IOBinder``, the list of all IO cell modules instantiated by the ``IOBinder``, and an optional function to be called inside the test harness. +This function is responsible for instantiating logic inside the ``TestHarness`` to appropriately drive the ``ChipTop`` IO ports created by the ``IOBinder``. +Conveniently, because the ``IOBinder`` is generating the port, it may also use the port inside this function, which prevents the ``BaseChipTop`` code from ever needing to access the port ``val``, thus having the ``IOBinder`` house all port specific code. +This scheme prevents the need to have two separate binder functions for each ``System`` trait. +When creating custom ``IOBinders`` it is important to use ``suggestName`` to name ports; otherwise Chisel will raise an exception trying to name the IOs. +The example ``IOBinders`` demonstrate this. -You could just as well create a custom harness module that attaches IOs explicitly. Instead, the IOBinders key provides a map from Scala traits to attachment behaviors. +As an example, the ``WithGPIOTiedOff`` IOBinder creates IO cells for the GPIO module(s) instantiated in the ``System``, then punches out new ``Analog`` ports for each one. +The test harness simply ties these off, but additional logic could be inserted to perform some kind of test in the ``TestHarness``. -For example, the ``WithSimAXIMemTiedOff`` IOBinder specifies that any ``Top`` which matches ``CanHaveMasterAXI4MemPortModuleImp`` will have a ``SimAXIMem`` connected. +.. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala + :language: scala + :start-after: DOC include start: WithGPIOTiedOff + :end-before: DOC include end: WithGPIOTiedOff + + +``IOBinders`` also do not need to create ports. Some ``IOBinders`` can simply insert circuitry inside the ``ChipTop`` layer. +For example, the ``WithSimAXIMemTiedOff`` IOBinder specifies that any ``System`` which matches ``CanHaveMasterAXI4MemPortModuleImp`` will have a ``SimAXIMem`` connected inside ``ChipTop``. .. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala :language: scala diff --git a/docs/Customization/Keys-Traits-Configs.rst b/docs/Customization/Keys-Traits-Configs.rst index ffa303b7..f4af3746 100644 --- a/docs/Customization/Keys-Traits-Configs.rst +++ b/docs/Customization/Keys-Traits-Configs.rst @@ -34,25 +34,25 @@ Accessing the value stored in the key is easy in Chisel, as long as the ``implic 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. +Typically, most custom blocks will need to modify the behavior of some pre-existing block. For example, the GCD widget needs the ``DigitalTop`` 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 ``DigitalTop``, 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 specify that the ``DigitalTop`` 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. +Top-level traits should be defined and documented in subprojects, alongside their corresponding keys. The traits should then be added to the ``DigitalTop`` 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. +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 ``DigitalTop`` to instantiate an additional port and concretely connect it to the GCD module. .. literalinclude:: ../../generators/chipyard/src/main/scala/example/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. +These traits are added to the default ``DigitalTop`` in Chipyard. -.. literalinclude:: ../../generators/chipyard/src/main/scala/Top.scala +.. literalinclude:: ../../generators/chipyard/src/main/scala/DigitalTop.scala :language: scala - :start-after: DOC include start: Top - :end-before: DOC include end: Top + :start-after: DOC include start: DigitalTop + :end-before: DOC include end: DigitalTop Config Fragments ---------------- diff --git a/docs/Customization/MMIO-Peripherals.rst b/docs/Customization/MMIO-Peripherals.rst index f6b429be..15ed5a00 100644 --- a/docs/Customization/MMIO-Peripherals.rst +++ b/docs/Customization/MMIO-Peripherals.rst @@ -87,21 +87,21 @@ For peripherals which instantiate a concrete module, or which need to be connect :start-after: DOC include start: GCD imp trait :end-before: DOC include end: GCD imp trait -Constructing the Top and Config -------------------------------- +Constructing the DigitalTop and Config +-------------------------------------- Now we want to mix our traits into the system as a whole. -This code is from ``generators/chipyard/src/main/scala/Top.scala``. +This code is from ``generators/chipyard/src/main/scala/DigitalTop.scala``. -.. literalinclude:: ../../generators/chipyard/src/main/scala/Top.scala +.. literalinclude:: ../../generators/chipyard/src/main/scala/DigitalTop.scala :language: scala - :start-after: DOC include start: Top - :end-before: DOC include end: Top + :start-after: DOC include start: DigitalTop + :end-before: DOC include end: DigitalTop 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. +The ``DigitalTop`` class contains the set of traits which parameterize and define the ``DigitalTop``. Typically these traits will optionally add IOs or peripherals to the ``DigitalTop``. +The ``DigitalTop`` class includes the pre-elaboration code and also a ``lazy val`` to produce the module implementation (hence ``LazyModule``). +The ``DigitalTopModule`` class is the actual RTL that gets synthesized. diff --git a/generators/chipyard/src/main/scala/ChipTop.scala b/generators/chipyard/src/main/scala/ChipTop.scala new file mode 100644 index 00000000..328891a8 --- /dev/null +++ b/generators/chipyard/src/main/scala/ChipTop.scala @@ -0,0 +1,102 @@ +package chipyard + +import chisel3._ + +import scala.collection.mutable.{ArrayBuffer} + +import freechips.rocketchip.config.{Parameters, Field} +import freechips.rocketchip.diplomacy.{LazyModule} +import freechips.rocketchip.util.{ResetCatchAndSync} +import chipyard.config.ConfigValName._ +import chipyard.iobinders.{IOBinders, TestHarnessFunction, IOBinderTuple} + +import barstools.iocell.chisel._ + +case object BuildSystem extends Field[Parameters => RawModule]((p: Parameters) => Module(LazyModule(new DigitalTop()(p)).suggestName("system").module)) + +/** + * The base class used for building chips. This constructor instantiates a module specified by the BuildSystem parameter, + * named "system", which is an instance of DigitalTop by default. The default clock and reset for "system" are set by two + * wires, "systemClock" and "systemReset", which are intended to be driven by traits mixed-in with this base class. + */ +abstract class BaseChipTop()(implicit val p: Parameters) extends RawModule with HasTestHarnessFunctions { + + // A publicly accessible list of IO cells (useful for a floorplanning tool, for example) + val iocells = ArrayBuffer.empty[IOCell] + // A list of functions to call in the test harness + val harnessFunctions = ArrayBuffer.empty[TestHarnessFunction] + // The system clock + val systemClock = Wire(Input(Clock())) + // The system reset (synchronous to clock) + val systemReset = Wire(Input(Bool())) + + // The system module specified by BuildSystem + val system = withClockAndReset(systemClock, systemReset) { p(BuildSystem)(p) } + + // Call all of the IOBinders and provide them with a default clock and reset + withClockAndReset(systemClock, systemReset) { + val (_ports, _iocells, _harnessFunctions) = p(IOBinders).values.map(_(system)).flatten.unzip3 + // We ignore _ports for now... + iocells ++= _iocells.flatten + harnessFunctions ++= _harnessFunctions.flatten + } + +} + +/** + * A simple clock and reset implementation that punches out clock and reset ports with the same + * names as the implicit clock and reset for standard Module classes. Reset is synchronous to + * clock, which may not be a good idea to use for tapeouts. + */ +trait HasChipTopSimpleClockAndReset { this: BaseChipTop => + + val (clock, systemClockIO) = IOCell.generateIOFromSignal(systemClock, Some("iocell_clock")) + val (reset, systemResetIO) = IOCell.generateIOFromSignal(systemReset, Some("iocell_reset")) + + iocells ++= systemClockIO + iocells ++= systemResetIO + + // Add a TestHarnessFunction that connects clock and reset + harnessFunctions += { (th: TestHarness) => { + // Connect clock; it's not done implicitly with RawModule + clock := th.clock + // Connect reset; it's not done implicitly with RawModule + // Note that we need to use dutReset, not harnessReset + reset := th.dutReset + Nil + } } + +} + +/** + * Variant of HasChipTopSimpleClockAndReset that adds a reset synchronizer so that the top-level reset + * can be asynchronous with clock, which is useful for tapeout configs. + */ +trait HasChipTopSimpleClockAndCaughtReset { this: BaseChipTop => + + val asyncResetCore = Wire(Input(Bool())) + systemReset := ResetCatchAndSync(systemClock, asyncResetCore) + + val (clock, systemClockIO) = IOCell.generateIOFromSignal(systemClock, Some("iocell_clock")) + val (areset, asyncResetIO) = IOCell.generateIOFromSignal(asyncResetCore, Some("iocell_areset")) + + iocells ++= systemClockIO + iocells ++= asyncResetIO + + // Add a TestHarnessFunction that connects clock and areset + harnessFunctions += { (th: TestHarness) => { + // Connect clock; it's not done implicitly with RawModule + clock := th.clock + // Connect reset; it's not done implicitly with RawModule + // Note that we need to use dutReset, not harnessReset + areset := th.dutReset + Nil + } } + +} + +class ChipTop()(implicit p: Parameters) extends BaseChipTop()(p) + with HasChipTopSimpleClockAndReset + +class ChipTopCaughtReset()(implicit p: Parameters) extends BaseChipTop()(p) + with HasChipTopSimpleClockAndCaughtReset diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index dae6e055..495c3367 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -21,7 +21,7 @@ import hwacha.{Hwacha} import sifive.blocks.devices.gpio._ import sifive.blocks.devices.uart._ -import chipyard.{BuildTop} +import chipyard.{BuildTop, BuildSystem, ChipTopCaughtReset} /** * TODO: Why do we need this? @@ -65,8 +65,8 @@ class WithL2TLBs(entries: Int) extends Config((site, here, up) => { )) }) -class WithTracegenTop extends Config((site, here, up) => { - case BuildTop => (p: Parameters) => Module(LazyModule(new tracegen.TraceGenSystem()(p)).suggestName("Top").module) +class WithTracegenSystem extends Config((site, here, up) => { + case BuildSystem => (p: Parameters) => Module(LazyModule(new tracegen.TraceGenSystem()(p)).suggestName("Top").module) }) @@ -150,3 +150,13 @@ class WithControlCore extends Config((site, here, up) => { ) case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) }) + + +/** + * Config fragment to use ChipTopCaughtReset as the top module, which adds a reset synchronizer to + * the top-level reset, allowing it to be asynchronous with the clock. + * NOTE: You must remember to set TOP=WithChipTopCaughtReset when building with this config + */ +class WithChipTopCaughtReset extends Config((site, here, up) => { + case BuildTop => (p: Parameters) => Module(new ChipTopCaughtReset()(p).suggestName("top")) +}) diff --git a/generators/chipyard/src/main/scala/Top.scala b/generators/chipyard/src/main/scala/DigitalTop.scala similarity index 86% rename from generators/chipyard/src/main/scala/Top.scala rename to generators/chipyard/src/main/scala/DigitalTop.scala index d81d779a..c7b3d497 100644 --- a/generators/chipyard/src/main/scala/Top.scala +++ b/generators/chipyard/src/main/scala/DigitalTop.scala @@ -11,8 +11,8 @@ import freechips.rocketchip.devices.tilelink._ // BOOM and/or Rocket Top Level Systems // ------------------------------------ -// DOC include start: Top -class Top(implicit p: Parameters) extends System +// DOC include start: DigitalTop +class DigitalTop(implicit p: Parameters) extends System with testchipip.CanHaveTraceIO // Enables optionally adding trace IO with testchipip.CanHaveBackingScratchpad // Enables optionally adding a backing scratchpad with testchipip.CanHavePeripheryBlockDevice // Enables optionally adding the block device @@ -23,10 +23,10 @@ class Top(implicit p: Parameters) extends System with chipyard.example.CanHavePeripheryInitZero // Enables optionally adding the initzero example widget with chipyard.example.CanHavePeripheryGCD // Enables optionally adding the GCD example widget { - override lazy val module = new TopModule(this) + override lazy val module = new DigitalTopModule(this) } -class TopModule[+L <: Top](l: L) extends SystemModule(l) +class DigitalTopModule[+L <: DigitalTop](l: L) extends SystemModule(l) with testchipip.CanHaveTraceIOModuleImp with testchipip.CanHavePeripheryBlockDeviceModuleImp with testchipip.CanHavePeripherySerialModuleImp @@ -35,4 +35,4 @@ class TopModule[+L <: Top](l: L) extends SystemModule(l) with icenet.CanHavePeripheryIceNICModuleImp with chipyard.example.CanHavePeripheryGCDModuleImp with freechips.rocketchip.util.DontTouch -// DOC include end: Top +// DOC include end: DigitalTop diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 938ecc5f..6388c3db 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -1,19 +1,22 @@ -package chipyard.iobinders +package chipyard +package object iobinders { import chisel3._ +import chisel3.experimental.{Analog, IO} import freechips.rocketchip.config.{Field, Config, Parameters} import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.devices.debug._ import freechips.rocketchip.subsystem._ -import freechips.rocketchip.system._ import freechips.rocketchip.util._ import sifive.blocks.devices.gpio._ import sifive.blocks.devices.uart._ +import barstools.iocell.chisel._ + import testchipip._ -import icenet._ +import icenet.{CanHavePeripheryIceNICModuleImp, SimNetwork, NicLoopback, NICKey} import tracegen.{HasTraceGenTilesModuleImp} import scala.reflect.{ClassTag} @@ -26,23 +29,32 @@ import scala.reflect.{ClassTag} // IO connection behavior for tops matching that trait. We use strings to enable // composition and overriding of IOBinders, much like how normal Keys in the config // system are used/ At elaboration, the testharness traverses this set of functions, -// and functions which match the type of the Top are evaluated. +// and functions which match the type of the DigitalTop are evaluated. // You can add your own binder by adding a new (key, fn) pair, typically by using // the OverrideIOBinder or ComposeIOBinder macros + // DOC include start: IOBinders -case object IOBinders extends Field[Map[String, (Clock, Bool, Bool, Any) => Seq[Any]]]( - Map[String, (Clock, Bool, Bool, Any) => Seq[Any]]().withDefaultValue((c: Clock, r: Bool, s: Bool, t: Any) => Nil) +// This type describes a function callable on the TestHarness instance. Its return type is unused. +type TestHarnessFunction = (chipyard.TestHarness) => Seq[Any] +// IOBinders will return a Seq of this tuple, which contains three fields: +// 1. A Seq containing all IO ports created by the IOBinder function +// 2. A Seq containing all IO cell modules created by the IOBinder function +// 3. An optional function to call inside the test harness (e.g. to connect the IOs) +type IOBinderTuple = (Seq[Data], Seq[IOCell], Option[TestHarnessFunction]) + +case object IOBinders extends Field[Map[String, (Any) => Seq[IOBinderTuple]]]( + Map[String, (Any) => Seq[IOBinderTuple]]().withDefaultValue((Any) => Nil) ) // This macro overrides previous matches on some Top mixin. This is useful for // binders which drive IO, since those typically cannot be composed -class OverrideIOBinder[T](fn: => (Clock, Bool, Bool, T) => Seq[Any])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { +class OverrideIOBinder[T](fn: => (T) => Seq[IOBinderTuple])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> - ((clock: Clock, reset: Bool, success: Bool, t: Any) => { + ((t: Any) => { t match { - case top: T => fn(clock, reset, success, top) + case system: T => fn(system) case _ => Nil } }) @@ -51,12 +63,12 @@ class OverrideIOBinder[T](fn: => (Clock, Bool, Bool, T) => Seq[Any])(implicit ta // This macro composes with previous matches on some Top mixin. This is useful for // annotation-like binders, since those can typically be composed -class ComposeIOBinder[T](fn: => (Clock, Bool, Bool, T) => Seq[Any])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { +class ComposeIOBinder[T](fn: => (T) => Seq[IOBinderTuple])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> - ((clock: Clock, reset: Bool, success: Bool, t: Any) => { + ((t: Any) => { t match { - case top: T => (up(IOBinders, site)(tag.runtimeClass.toString)(clock, reset, success, top) - ++ fn(clock, reset, success, top)) + case system: T => (up(IOBinders, site)(tag.runtimeClass.toString)(system) + ++ fn(system)) case _ => Nil } }) @@ -65,74 +77,146 @@ class ComposeIOBinder[T](fn: => (Clock, Bool, Bool, T) => Seq[Any])(implicit tag // DOC include end: IOBinders +object AddIOCells { + /** + * Add IO cells to a SiFive GPIO devices and name the IO ports. + * @param gpios A Seq of GPIO port bundles + * @param genFn A callable function to generate a DigitalGPIOCell module to use + * @return Returns a tuple of (a 2D Seq of Analog IOs corresponding to individual GPIO pins; a 2D Seq of IOCell module references) + */ + def gpio(gpios: Seq[GPIOPortIO], genFn: () => DigitalGPIOCell = IOCell.genericGPIO): (Seq[Seq[Analog]], Seq[Seq[IOCell]]) = { + gpios.zipWithIndex.map({ case (gpio, i) => + gpio.pins.zipWithIndex.map({ case (pin, j) => + val g = IO(Analog(1.W)) + g.suggestName("gpio_${i}_${j}") + val iocell = genFn() + iocell.suggestName(s"iocell_gpio_${i}_${j}") + iocell.io.o := pin.o.oval + iocell.io.oe := pin.o.oe + iocell.io.ie := pin.o.ie + pin.i.ival := iocell.io.i + iocell.io.pad <> g + (g, iocell) + }).unzip + }).unzip + } + + /** + * Add IO cells to a SiFive UART devices and name the IO ports. + * @param gpios A Seq of UART port bundles + * @return Returns a tuple of (A Seq of top-level UARTPortIO IOs; a 2D Seq of IOCell module references) + */ + def uart(uartPins: Seq[UARTPortIO]): (Seq[UARTPortIO], Seq[Seq[IOCell]]) = { + uartPins.zipWithIndex.map({ case (u, i) => + val (port, ios) = IOCell.generateIOFromSignal(u, Some(s"iocell_uart_${i}")) + port.suggestName(s"uart_${i}") + (port, ios) + }).unzip + } + + /** + * Add IO cells to a debug module and name the IO ports. + * @param gpios A PSDIO bundle + * @param debugOpt An optional DebugIO bundle + * @return Returns a tuple3 of (Top-level PSDIO IO; Optional top-level DebugIO IO; a list of IOCell module references) + */ + def debug(psd: PSDIO, debugOpt: Option[DebugIO]): (PSDIO, Option[DebugIO], Seq[IOCell]) = { + val (psdPort, psdIOs) = IOCell.generateIOFromSignal(psd, Some("iocell_psd")) + val optTuple = debugOpt.map(d => IOCell.generateIOFromSignal(d, Some("iocell_debug"))) + val debugPortOpt: Option[DebugIO] = optTuple.map(_._1) + val debugIOs: Seq[IOCell] = optTuple.map(_._2).toSeq.flatten + debugPortOpt.foreach(_.suggestName("debug")) + psdPort.suggestName("psd") + (psdPort, debugPortOpt, psdIOs ++ debugIOs) + } + + /** + * Add IO cells to a serial module and name the IO ports. + * @param serial A SerialIO bundle + * @return Returns a tuple of (Top-level SerialIO IO; a list of IOCell module references) + */ + def serial(serial: SerialIO): (SerialIO, Seq[IOCell]) = { + val (port, ios) = IOCell.generateIOFromSignal(serial, Some("iocell_serial")) + port.suggestName("serial") + (port, ios) + } +} + +// DOC include start: WithGPIOTiedOff class WithGPIOTiedOff extends OverrideIOBinder({ - (c, r, s, top: HasPeripheryGPIOModuleImp) => top.gpio.map(gpio => gpio.pins.map(p => p.i.ival := false.B)); Nil + (system: HasPeripheryGPIOModuleImp) => { + val (ports2d, ioCells2d) = AddIOCells.gpio(system.gpio) + val harnessFn = (th: chipyard.TestHarness) => { ports2d.flatten.foreach(_ <> AnalogConst(0)); Nil } + Seq((ports2d.flatten, ioCells2d.flatten, Some(harnessFn))) + } +}) +// DOC include end: WithGPIOTiedOff + +class WithUARTAdapter extends OverrideIOBinder({ + (system: HasPeripheryUARTModuleImp) => { + val (ports, ioCells2d) = AddIOCells.uart(system.uart) + val harnessFn = (th: chipyard.TestHarness) => { UARTAdapter.connect(ports)(system.p); Nil } + Seq((ports, ioCells2d.flatten, Some(harnessFn))) + } }) class WithSimBlockDevice extends OverrideIOBinder({ - (c, r, s, top: CanHavePeripheryBlockDeviceModuleImp) => top.connectSimBlockDevice(c, r); Nil + (system: CanHavePeripheryBlockDeviceModuleImp) => system.connectSimBlockDevice(system.clock, system.reset.asBool); Nil }) class WithBlockDeviceModel extends OverrideIOBinder({ - (c, r, s, top: CanHavePeripheryBlockDeviceModuleImp) => top.connectBlockDeviceModel(); Nil + (system: CanHavePeripheryBlockDeviceModuleImp) => system.connectBlockDeviceModel(); Nil }) class WithLoopbackNIC extends OverrideIOBinder({ - (c, r, s, top: CanHavePeripheryIceNICModuleImp) => top.connectNicLoopback(); Nil + (system: CanHavePeripheryIceNICModuleImp) => system.connectNicLoopback(); Nil }) class WithSimNIC extends OverrideIOBinder({ - (c, r, s, top: CanHavePeripheryIceNICModuleImp) => top.connectSimNetwork(c, r); Nil -}) - -class WithUARTAdapter extends OverrideIOBinder({ - (c, r, s, top: HasPeripheryUARTModuleImp) => { - val defaultBaudRate = 115200 // matches sifive-blocks uart baudrate - top.uart.zipWithIndex.foreach{ case (dut_io, i) => - val uart_sim = Module(new UARTAdapter(i, defaultBaudRate)(top.p)) - uart_sim.io.uart.txd := dut_io.txd - dut_io.rxd := uart_sim.io.uart.rxd - } - Nil - } + (system: CanHavePeripheryIceNICModuleImp) => system.connectSimNetwork(system.clock, system.reset.asBool); Nil }) // DOC include start: WithSimAXIMem class WithSimAXIMem extends OverrideIOBinder({ - (c, r, s, top: CanHaveMasterAXI4MemPortModuleImp) => top.connectSimAXIMem(); Nil + (system: CanHaveMasterAXI4MemPortModuleImp) => system.connectSimAXIMem(); Nil }) // DOC include end: WithSimAXIMem class WithBlackBoxSimMem extends OverrideIOBinder({ - (clock, reset, _, top: CanHaveMasterAXI4MemPortModuleImp) => { - (top.mem_axi4 zip top.outer.memAXI4Node).foreach { case (io, node) => - val memSize = top.p(ExtMem).get.master.size - val lineSize = top.p(CacheBlockBytes) + (system: CanHaveMasterAXI4MemPortModuleImp) => { + (system.mem_axi4 zip system.outer.memAXI4Node).foreach { case (io, node) => + val memSize = system.p(ExtMem).get.master.size + val lineSize = system.p(CacheBlockBytes) (io zip node.in).foreach { case (axi4, (_, edge)) => val mem = Module(new SimDRAM(memSize, lineSize, edge.bundle)) mem.io.axi <> axi4 - mem.io.clock := clock - mem.io.reset := reset + mem.io.clock := system.clock + mem.io.reset := system.reset } }; Nil } }) class WithSimAXIMMIO extends OverrideIOBinder({ - (c, r, s, top: CanHaveMasterAXI4MMIOPortModuleImp) => top.connectSimAXIMMIO(); Nil + (system: CanHaveMasterAXI4MMIOPortModuleImp) => system.connectSimAXIMMIO(); Nil }) class WithDontTouchPorts extends OverrideIOBinder({ - (c, r, s, top: DontTouch) => top.dontTouchPorts(); Nil + (system: DontTouch) => system.dontTouchPorts(); Nil }) class WithTieOffInterrupts extends OverrideIOBinder({ - (c, r, s, top: HasExtInterruptsBundle) => top.tieOffInterrupts(); Nil + (system: HasExtInterruptsModuleImp) => { + val (port, ioCells) = IOCell.generateIOFromSignal(system.interrupts, Some("iocell_interrupts")) + port.suggestName("interrupts") + val harnessFn = (th: chipyard.TestHarness) => { port := 0.U; Nil } + Seq((Seq(port), ioCells, Some(harnessFn))) + } }) class WithTieOffL2FBusAXI extends OverrideIOBinder({ - (c, r, s, top: CanHaveSlaveAXI4PortModuleImp) => { - top.l2_frontend_bus_axi4.foreach(axi => { + (system: CanHaveSlaveAXI4PortModuleImp) => { + system.l2_frontend_bus_axi4.foreach(axi => { axi.tieoff() experimental.DataMirror.directionOf(axi.ar.ready) match { case ActualDirection.Input => @@ -142,6 +226,7 @@ class WithTieOffL2FBusAXI extends OverrideIOBinder({ axi.aw.bits := DontCare axi.ar.bits := DontCare axi.w.bits := DontCare + case _ => throw new Exception("Unknown AXI port direction") } }) Nil @@ -149,38 +234,62 @@ class WithTieOffL2FBusAXI extends OverrideIOBinder({ }) class WithTiedOffDebug extends OverrideIOBinder({ - (c, r, s, top: HasPeripheryDebugModuleImp) => { - Debug.tieoffDebug(top.debug, top.psd) - // tieoffDebug doesn't actually tie everything off :/ - top.debug.foreach(_.clockeddmi.foreach({ cdmi => cdmi.dmi.req.bits := DontCare })) - Nil + (system: HasPeripheryDebugModuleImp) => { + val (psdPort, debugPortOpt, ioCells) = AddIOCells.debug(system.psd, system.debug) + val harnessFn = (th: chipyard.TestHarness) => { + Debug.tieoffDebug(debugPortOpt, psdPort) + // tieoffDebug doesn't actually tie everything off :/ + debugPortOpt.foreach(_.clockeddmi.foreach({ cdmi => cdmi.dmi.req.bits := DontCare })) + Nil + } + Seq((Seq(psdPort) ++ debugPortOpt.toSeq, ioCells, Some(harnessFn))) } }) -class WithSimSerial extends OverrideIOBinder({ - (c, r, s, top: CanHavePeripherySerialModuleImp) => { - val ser_success = top.connectSimSerial() - when (ser_success) { s := true.B } - Nil +class WithSimDebug extends OverrideIOBinder({ + (system: HasPeripheryDebugModuleImp) => { + val (psdPort, debugPortOpt, ioCells) = AddIOCells.debug(system.psd, system.debug) + val harnessFn = (th: chipyard.TestHarness) => { + val dtm_success = Wire(Bool()) + Debug.connectDebug(debugPortOpt, psdPort, th.clock, th.harnessReset, dtm_success)(system.p) + when (dtm_success) { th.success := true.B } + th.dutReset := th.harnessReset | debugPortOpt.map { debug => AsyncResetReg(debug.ndreset).asBool }.getOrElse(false.B) + Nil + } + Seq((Seq(psdPort) ++ debugPortOpt.toSeq, ioCells, Some(harnessFn))) } }) class WithTiedOffSerial extends OverrideIOBinder({ - (c, r, s, top: CanHavePeripherySerialModuleImp) => top.tieoffSerial(); Nil + (system: CanHavePeripherySerialModuleImp) => system.serial.map({ serial => + val (port, ioCells) = AddIOCells.serial(serial) + val harnessFn = (th: chipyard.TestHarness) => { + SerialAdapter.tieoff(port) + Nil + } + Seq((Seq(port), ioCells, Some(harnessFn))) + }).getOrElse(Nil) }) +class WithSimSerial extends OverrideIOBinder({ + (system: CanHavePeripherySerialModuleImp) => system.serial.map({ serial => + val (port, ioCells) = AddIOCells.serial(serial) + val harnessFn = (th: chipyard.TestHarness) => { + val ser_success = SerialAdapter.connectSimSerial(port, th.clock, th.harnessReset) + when (ser_success) { th.success := true.B } + Nil + } + Seq((Seq(port), ioCells, Some(harnessFn))) + }).getOrElse(Nil) +}) -class WithSimDebug extends OverrideIOBinder({ - (c, r, s, top: HasPeripheryDebugModuleImp) => { - val dtm_success = Wire(Bool()) - top.reset := r | top.debug.map { debug => AsyncResetReg(debug.ndreset) }.getOrElse(false.B) - Debug.connectDebug(top.debug, top.psd, c, r, dtm_success)(top.p) - when (dtm_success) { s := true.B } - Nil +class WithTraceGenSuccessBinder extends OverrideIOBinder({ + (system: HasTraceGenTilesModuleImp) => { + val (successPort, ioCells) = IOCell.generateIOFromSignal(system.success, Some("iocell_success")) + successPort.suggestName("success") + val harnessFn = (th: chipyard.TestHarness) => { when (successPort) { th.success := true.B }; Nil } + Seq((Seq(successPort), ioCells, Some(harnessFn))) } }) - -class WithTraceGenSuccessBinder extends OverrideIOBinder({ - (c, r, s, top: HasTraceGenTilesModuleImp) => when (top.success) { s := true.B }; Nil -}) +} diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index ca861288..4aaef747 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -1,23 +1,21 @@ package chipyard import chisel3._ -import chisel3.experimental._ -import firrtl.transforms.{BlackBoxResourceAnno, BlackBoxSourceHelper} - -import freechips.rocketchip.diplomacy.LazyModule +import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.config.{Field, Parameters} -import freechips.rocketchip.util.GeneratorApp -import freechips.rocketchip.devices.debug.{Debug} - +import chipyard.iobinders.{TestHarnessFunction} import chipyard.config.ConfigValName._ -import chipyard.iobinders.{IOBinders} // ------------------------------- // BOOM and/or Rocket Test Harness // ------------------------------- -case object BuildTop extends Field[Parameters => Any]((p: Parameters) => Module(LazyModule(new Top()(p)).suggestName("top").module)) +case object BuildTop extends Field[Parameters => HasTestHarnessFunctions]((p: Parameters) => Module(new ChipTop()(p))) + +trait HasTestHarnessFunctions { + val harnessFunctions: Seq[TestHarnessFunction] +} class TestHarness(implicit val p: Parameters) extends Module { val io = IO(new Bundle { @@ -26,5 +24,15 @@ class TestHarness(implicit val p: Parameters) extends Module { val dut = p(BuildTop)(p) io.success := false.B - p(IOBinders).values.map(fn => fn(clock, reset.asBool, io.success, dut)) + + // dutReset can be overridden via a harnessFunction, but by default it is just reset + val dutReset = Wire(Bool()) + dutReset := reset + + dut.harnessFunctions.foreach(_(this)) + + def success = io.success + def harnessReset = this.reset.asBool + } + diff --git a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala index ead38869..fefa271d 100644 --- a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala +++ b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala @@ -6,21 +6,21 @@ import freechips.rocketchip.rocket.{DCacheParams} class TraceGenConfig extends Config( new chipyard.iobinders.WithBlackBoxSimMem ++ new chipyard.iobinders.WithTraceGenSuccessBinder ++ - new chipyard.config.WithTracegenTop ++ + new chipyard.config.WithTracegenSystem ++ new tracegen.WithTraceGen(List.fill(2) { DCacheParams(nMSHRs = 0, nSets = 16, nWays = 2) }) ++ new freechips.rocketchip.system.BaseConfig) class NonBlockingTraceGenConfig extends Config( new chipyard.iobinders.WithBlackBoxSimMem ++ new chipyard.iobinders.WithTraceGenSuccessBinder ++ - new chipyard.config.WithTracegenTop ++ + new chipyard.config.WithTracegenSystem ++ new tracegen.WithTraceGen(List.fill(2) { DCacheParams(nMSHRs = 2, nSets = 16, nWays = 2) }) ++ new freechips.rocketchip.system.BaseConfig) class BoomTraceGenConfig extends Config( new chipyard.iobinders.WithBlackBoxSimMem ++ new chipyard.iobinders.WithTraceGenSuccessBinder ++ - new chipyard.config.WithTracegenTop ++ + new chipyard.config.WithTracegenSystem ++ new tracegen.WithBoomTraceGen(List.fill(2) { DCacheParams(nMSHRs = 8, nSets = 16, nWays = 2) }) ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.system.BaseConfig) @@ -28,7 +28,7 @@ class BoomTraceGenConfig extends Config( class NonBlockingTraceGenL2Config extends Config( new chipyard.iobinders.WithBlackBoxSimMem ++ new chipyard.iobinders.WithTraceGenSuccessBinder ++ - new chipyard.config.WithTracegenTop ++ + new chipyard.config.WithTracegenSystem ++ new tracegen.WithL2TraceGen(List.fill(2)(DCacheParams(nMSHRs = 2, nSets = 16, nWays = 4))) ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.system.BaseConfig) @@ -36,7 +36,7 @@ class NonBlockingTraceGenL2Config extends Config( class NonBlockingTraceGenL2RingConfig extends Config( new chipyard.iobinders.WithBlackBoxSimMem ++ new chipyard.iobinders.WithTraceGenSuccessBinder ++ - new chipyard.config.WithTracegenTop ++ + new chipyard.config.WithTracegenSystem ++ new tracegen.WithL2TraceGen(List.fill(2)(DCacheParams(nMSHRs = 2, nSets = 16, nWays = 4))) ++ new testchipip.WithRingSystemBus ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index ebd12d1b..ae6c82fa 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -7,10 +7,11 @@ import chisel3.experimental.annotate import freechips.rocketchip.config.{Field, Config, Parameters} import freechips.rocketchip.diplomacy.{LazyModule} -import freechips.rocketchip.devices.debug.HasPeripheryDebugModuleImp -import freechips.rocketchip.subsystem.{CanHaveMasterAXI4MemPortModuleImp} +import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebugModuleImp} +import freechips.rocketchip.subsystem.{CanHaveMasterAXI4MemPortModuleImp, HasExtInterruptsModuleImp} import freechips.rocketchip.tile.{RocketTile} import sifive.blocks.devices.uart.HasPeripheryUARTModuleImp +import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp} import testchipip.{CanHavePeripherySerialModuleImp, CanHavePeripheryBlockDeviceModuleImp, CanHaveTraceIOModuleImp} import icenet.CanHavePeripheryIceNICModuleImp @@ -29,56 +30,55 @@ import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder} import chipyard.HasChipyardTilesModuleImp class WithSerialBridge extends OverrideIOBinder({ - (c, r, s, target: CanHavePeripherySerialModuleImp) => - target.serial.map(s => SerialBridge(target.clock, s)(target.p)).toSeq + (system: CanHavePeripherySerialModuleImp) => + system.serial.foreach(s => SerialBridge(system.clock, s)(system.p)); Nil }) class WithNICBridge extends OverrideIOBinder({ - (c, r, s, target: CanHavePeripheryIceNICModuleImp) => - target.net.map(n => NICBridge(target.clock, n)(target.p)).toSeq + (system: CanHavePeripheryIceNICModuleImp) => + system.net.foreach(n => NICBridge(system.clock, n)(system.p)); Nil }) class WithUARTBridge extends OverrideIOBinder({ - (c, r, s, target: HasPeripheryUARTModuleImp) => - target.uart.map(u => UARTBridge(target.clock, u)(target.p)).toSeq + (system: HasPeripheryUARTModuleImp) => + system.uart.foreach(u => UARTBridge(system.clock, u)(system.p)); Nil }) class WithBlockDeviceBridge extends OverrideIOBinder({ - (c, r, s, target: CanHavePeripheryBlockDeviceModuleImp) => - target.bdev.map(b => BlockDevBridge(target.clock, b, target.reset.toBool)(target.p)).toSeq + (system: CanHavePeripheryBlockDeviceModuleImp) => + system.bdev.foreach(b => BlockDevBridge(system.clock, b, system.reset.toBool)(system.p)); Nil }) class WithFASEDBridge extends OverrideIOBinder({ - (c, r, s, t: CanHaveMasterAXI4MemPortModuleImp) => { - implicit val p = t.p - (t.mem_axi4 zip t.outer.memAXI4Node).flatMap({ case (io, node) => + (system: CanHaveMasterAXI4MemPortModuleImp) => { + implicit val p = system.p + (system.mem_axi4 zip system.outer.memAXI4Node).flatMap({ case (io, node) => (io zip node.in).map({ case (axi4Bundle, (_, edge)) => val nastiKey = NastiParameters(axi4Bundle.r.bits.data.getWidth, axi4Bundle.ar.bits.addr.getWidth, axi4Bundle.ar.bits.id.getWidth) - FASEDBridge(t.clock, axi4Bundle, t.reset.toBool, + FASEDBridge(system.clock, axi4Bundle, system.reset.toBool, CompleteConfig(p(firesim.configs.MemModelKey), nastiKey, Some(AXI4EdgeSummary(edge)))) }) - }).toSeq + }) + Nil } }) class WithTracerVBridge extends OverrideIOBinder({ - (c, r, s, target: CanHaveTraceIOModuleImp) => target.traceIO match { - case Some(t) => t.traces.map(tileTrace => TracerVBridge(tileTrace)(target.p)) - case None => Nil - } + (system: CanHaveTraceIOModuleImp) => + system.traceIO.foreach(_.traces.map(tileTrace => TracerVBridge(tileTrace)(system.p))); Nil }) class WithTraceGenBridge extends OverrideIOBinder({ - (c, r, s, target: HasTraceGenTilesModuleImp) => - Seq(GroundTestBridge(target.clock, target.success)(target.p)) + (system: HasTraceGenTilesModuleImp) => + GroundTestBridge(system.clock, system.success)(system.p); Nil }) class WithFireSimMultiCycleRegfile extends ComposeIOBinder({ - (c, r, s, target: HasChipyardTilesModuleImp) => { - target.outer.tiles.map { + (system: HasChipyardTilesModuleImp) => { + system.outer.tiles.map { case r: RocketTile => { annotate(MemModelAnnotation(r.module.core.rocketImpl.rf.rf)) r.module.fpuOpt.foreach(fpu => annotate(MemModelAnnotation(fpu.fpuImpl.regfile))) @@ -100,13 +100,31 @@ class WithFireSimMultiCycleRegfile extends ComposeIOBinder({ } }) +class WithTiedOffSystemGPIO extends OverrideIOBinder({ + (system: HasPeripheryGPIOModuleImp) => + system.gpio.foreach(_.pins.foreach(_.i.ival := false.B)); Nil +}) + +class WithTiedOffSystemDebug extends OverrideIOBinder({ + (system: HasPeripheryDebugModuleImp) => { + Debug.tieoffDebug(system.debug, system.psd) + // tieoffDebug doesn't actually tie everything off :/ + system.debug.foreach(_.clockeddmi.foreach({ cdmi => cdmi.dmi.req.bits := DontCare })) + Nil + } +}) + +class WithTiedOffSystemInterrupts extends OverrideIOBinder({ + (system: HasExtInterruptsModuleImp) => + system.interrupts := 0.U; Nil +}) // Shorthand to register all of the provided bridges above class WithDefaultFireSimBridges extends Config( - new chipyard.iobinders.WithGPIOTiedOff ++ - new chipyard.iobinders.WithTiedOffDebug ++ - new chipyard.iobinders.WithTieOffInterrupts ++ + new WithTiedOffSystemGPIO ++ + new WithTiedOffSystemDebug ++ + new WithTiedOffSystemInterrupts ++ new WithSerialBridge ++ new WithNICBridge ++ new WithUARTBridge ++ diff --git a/generators/firechip/src/main/scala/FireSim.scala b/generators/firechip/src/main/scala/FireSim.scala index 221548c3..157b8907 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -9,7 +9,7 @@ import freechips.rocketchip.diplomacy.{LazyModule} import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge} -import chipyard.{BuildTop} +import chipyard.{BuildSystem} import chipyard.iobinders.{IOBinders} // Determines the number of times to instantiate the DUT in the harness. @@ -26,14 +26,14 @@ class FireSim(implicit val p: Parameters) extends RawModule { val reset = WireInit(false.B) withClockAndReset(clock, reset) { // Instantiate multiple instances of the DUT to implement supernode - val targets = Seq.fill(p(NumNodes))(p(BuildTop)(p)) + val targets = Seq.fill(p(NumNodes))(p(BuildSystem)(p)) val peekPokeBridge = PeekPokeBridge(clock, reset) // A Seq of partial functions that will instantiate the right bridge only // if that Mixin trait is present in the target's class instance // // Apply each partial function to each DUT instance for ((target) <- targets) { - p(IOBinders).values.map(fn => fn(clock, reset.asBool, false.B, target)) + p(IOBinders).values.map(_(target)) } } } diff --git a/generators/firechip/src/main/scala/FireSimMulticlockPOC.scala b/generators/firechip/src/main/scala/FireSimMulticlockPOC.scala index 318e3547..b16f99c7 100644 --- a/generators/firechip/src/main/scala/FireSimMulticlockPOC.scala +++ b/generators/firechip/src/main/scala/FireSimMulticlockPOC.scala @@ -14,7 +14,7 @@ import boom.common.{BoomTilesKey, BoomCrossingKey} import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock} import firesim.configs._ -import chipyard.{BuildTop, Top, TopModule} +import chipyard.{BuildSystem, DigitalTop, DigitalTopModule} import chipyard.config.ConfigValName._ import chipyard.iobinders.{IOBinders} @@ -64,7 +64,7 @@ class WithSingleRationalTileDomain(multiplier: Int, divisor: Int) extends Config class HalfRateUncore extends WithSingleRationalTileDomain(2,1) class WithFiresimMulticlockTop extends Config((site, here, up) => { - case BuildTop => (p: Parameters) => Module(LazyModule(new FiresimMulticlockTop()(p)).suggestName("Top").module) + case BuildSystem => (p: Parameters) => Module(LazyModule(new FiresimMulticlockTop()(p)).suggestName("system").module) }) // Complete Config @@ -74,12 +74,12 @@ class FireSimQuadRocketMulticlockConfig extends Config( new FireSimQuadRocketConfig) // Top Definition -class FiresimMulticlockTop(implicit p: Parameters) extends chipyard.Top +class FiresimMulticlockTop(implicit p: Parameters) extends chipyard.DigitalTop { override lazy val module = new FiresimMulticlockTopModule(this) } -class FiresimMulticlockTopModule[+L <: Top](l: L) extends chipyard.TopModule(l) with HasFireSimClockingImp +class FiresimMulticlockTopModule[+L <: DigitalTop](l: L) extends chipyard.DigitalTopModule(l) with HasFireSimClockingImp // Harness Definition class FireSimMulticlockPOC(implicit val p: Parameters) extends RawModule { @@ -88,14 +88,14 @@ class FireSimMulticlockPOC(implicit val p: Parameters) extends RawModule { val reset = WireInit(false.B) withClockAndReset(refClock, reset) { // Instantiate multiple instances of the DUT to implement supernode - val targets = Seq.fill(p(NumNodes))(p(BuildTop)(p)) + val targets = Seq.fill(p(NumNodes))(p(BuildSystem)(p)) val peekPokeBridge = PeekPokeBridge(refClock, reset) // A Seq of partial functions that will instantiate the right bridge only // if that Mixin trait is present in the target's class instance // // Apply each partial function to each DUT instance for ((target) <- targets) { - p(IOBinders).values.map(fn => fn(refClock, reset.asBool, false.B, target)) + p(IOBinders).values.map(_(target)) } targets.collect({ case t: HasAdditionalClocks => t.clocks := clockBridge.io.clocks }) } diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 1f9791ee..04d9a8f6 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -24,7 +24,6 @@ import testchipip.WithRingSystemBus import firesim.bridges._ import firesim.configs._ -import chipyard.{BuildTop} import chipyard.config.ConfigValName._ class WithBootROM extends Config((site, here, up) => { diff --git a/generators/icenet b/generators/icenet index f2272284..b1f957e6 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit f22722847444ecfcd5369f1b33547727d051b834 +Subproject commit b1f957e6eb022c662f0fb33c7ddfbddc686bfde5 diff --git a/generators/testchipip b/generators/testchipip index 30d44252..d06d7c7d 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 30d44252e8a990da38f1fed6ac6c810fb42dae28 +Subproject commit d06d7c7dc274420a5fc5600ba8bdb2003cc9b0cd diff --git a/scripts/tutorial-patches/build.sbt.patch b/scripts/tutorial-patches/build.sbt.patch index 422c59c8..6f20a3ce 100644 --- a/scripts/tutorial-patches/build.sbt.patch +++ b/scripts/tutorial-patches/build.sbt.patch @@ -5,7 +5,7 @@ index a633066..3df8b74 100644 @@ -124,7 +124,7 @@ lazy val testchipip = (project in file("generators/testchipip")) lazy val chipyard = conditionalDependsOn(project in file("generators/chipyard")) - .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities, + .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities, iocell, - sha3, // On separate line to allow for cleaner tutorial-setup patches +// sha3, // On separate line to allow for cleaner tutorial-setup patches gemmini, icenet, tracegen, ariane) diff --git a/tools/barstools b/tools/barstools index 63d74bc1..db677636 160000 --- a/tools/barstools +++ b/tools/barstools @@ -1 +1 @@ -Subproject commit 63d74bc177cb070126eb0e662ff0ea500722a8d7 +Subproject commit db6776367c7a8f4850266d72f81cd4c90561731a diff --git a/variables.mk b/variables.mk index 5692296b..4953c968 100644 --- a/variables.mk +++ b/variables.mk @@ -36,7 +36,7 @@ ifeq ($(SUB_PROJECT),chipyard) CONFIG_PACKAGE ?= $(SBT_PROJECT) GENERATOR_PACKAGE ?= $(SBT_PROJECT) TB ?= TestDriver - TOP ?= Top + TOP ?= ChipTop endif # for Rocket-chip developers ifeq ($(SUB_PROJECT),rocketchip)