Merge remote-tracking branch 'origin/dev' into diplomatic-bridges
This commit is contained in:
@@ -145,6 +145,17 @@ jobs:
|
||||
name: Check that the tutorial-setup patches apply
|
||||
command: |
|
||||
scripts/tutorial-setup.sh
|
||||
documentation-check:
|
||||
executor: main-env
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Check that documentation builds with no warnings/errors
|
||||
command: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y python3-pip
|
||||
sudo pip3 install -r docs/requirements.txt
|
||||
make -C docs html
|
||||
|
||||
install-riscv-toolchain:
|
||||
executor: main-env
|
||||
@@ -357,6 +368,9 @@ workflows:
|
||||
# Attempt to apply the tutorial patches
|
||||
- tutorial-setup-check
|
||||
|
||||
# Check that documentation builds
|
||||
- documentation-check
|
||||
|
||||
# Build extra tests
|
||||
- build-extra-tests:
|
||||
requires:
|
||||
|
||||
@@ -10,7 +10,7 @@ To get started using Chipyard, see the documentation on the Chipyard documentati
|
||||
|
||||
Chipyard is an open source framework for agile development of Chisel-based systems-on-chip.
|
||||
It will allow you to leverage the Chisel HDL, Rocket Chip SoC generator, and other [Berkeley][berkeley] projects to produce a [RISC-V][riscv] SoC with everything from MMIO-mapped peripherals to custom accelerators.
|
||||
Chipyard contains processor cores ([Rocket][rocket-chip], [BOOM][boom], [Ariane][ariane]), accelerators ([Hwacha][hwacha]), memory systems, and additional peripherals and tooling to help create a full featured SoC.
|
||||
Chipyard contains processor cores ([Rocket][rocket-chip], [BOOM][boom], [Ariane][ariane]), accelerators ([Hwacha][hwacha], [Gemmini][gemmini]), memory systems, and additional peripherals and tooling to help create a full featured SoC.
|
||||
Chipyard supports multiple concurrent flows of agile hardware development, including software RTL simulation, FPGA-accelerated simulation ([FireSim][firesim]), automated VLSI flows ([Hammer][hammer]), and software workload generation for bare-metal and Linux-based systems ([FireMarshal][firemarshal]).
|
||||
Chipyard is actively developed in the [Berkeley Architecture Research Group][ucb-bar] in the [Electrical Engineering and Computer Sciences Department][eecs] at the [University of California, Berkeley][berkeley].
|
||||
|
||||
@@ -64,3 +64,4 @@ These publications cover many of the internal components used in Chipyard. Howev
|
||||
[boom]: https://github.com/ucb-bar/riscv-boom
|
||||
[firemarshal]: https://github.com/firesim/FireMarshal/
|
||||
[ariane]: https://github.com/pulp-platform/ariane/
|
||||
[gemmini]: https://github.com/ucb-bar/gemmini
|
||||
|
||||
@@ -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)
|
||||
|
||||
47
common.mk
47
common.mk
@@ -3,15 +3,26 @@
|
||||
#########################################################################################
|
||||
SHELL=/bin/bash
|
||||
|
||||
#########################################################################################
|
||||
# extra make variables/rules from subprojects
|
||||
#
|
||||
# EXTRA_GENERATOR_REQS - requirements needed for the main generator
|
||||
# EXTRA_SIM_FLAGS - runtime simulation flags
|
||||
# EXTRA_SIM_CC_FLAGS - cc flags for simulators
|
||||
# EXTRA_SIM_SOURCES - simulation sources needed for simulator
|
||||
# EXTRA_SIM_REQS - requirements to build the simulator
|
||||
#########################################################################################
|
||||
include $(base_dir)/generators/ariane/ariane.mk
|
||||
include $(base_dir)/generators/tracegen/tracegen.mk
|
||||
|
||||
#########################################################################################
|
||||
# variables to get all *.scala files
|
||||
#########################################################################################
|
||||
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)
|
||||
ARIANE_VLOG_SOURCES = $(call lookup_srcs,$(base_dir)/generators/ariane,sv) $(call lookup_srcs,$(base_dir)/generators/ariane,v)
|
||||
|
||||
#########################################################################################
|
||||
# rocket and testchipip classes
|
||||
@@ -45,7 +56,7 @@ $(FIRRTL_FILE) $(ANNO_FILE): generator_temp
|
||||
@echo "" > /dev/null
|
||||
|
||||
# AG: must re-elaborate if ariane sources have changed... otherwise just run firrtl compile
|
||||
generator_temp: $(SCALA_SOURCES) $(ARIANE_VLOG_SOURCES) $(sim_files)
|
||||
generator_temp: $(SCALA_SOURCES) $(sim_files) $(EXTRA_GENERATOR_REQS)
|
||||
mkdir -p $(build_dir)
|
||||
cd $(base_dir) && $(SBT) "project $(SBT_PROJECT)" "runMain $(GENERATOR_PACKAGE).Generator $(build_dir) $(MODEL_PACKAGE) $(MODEL) $(CONFIG_PACKAGE) $(CONFIG)"
|
||||
|
||||
@@ -105,19 +116,19 @@ verilog: $(sim_vsrcs)
|
||||
#########################################################################################
|
||||
.PHONY: run-binary run-binary-fast run-binary-debug run-fast
|
||||
run-binary: $(sim)
|
||||
(set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $(BINARY) </dev/null 2> >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log)
|
||||
(set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $(BINARY) </dev/null 2> >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log)
|
||||
|
||||
#########################################################################################
|
||||
# helper rules to run simulator as fast as possible
|
||||
#########################################################################################
|
||||
run-binary-fast: $(sim)
|
||||
(set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(PERMISSIVE_OFF) $(BINARY) </dev/null | tee $(sim_out_name).log)
|
||||
(set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(PERMISSIVE_OFF) $(BINARY) </dev/null | tee $(sim_out_name).log)
|
||||
|
||||
#########################################################################################
|
||||
# helper rules to run simulator with as much debug info as possible
|
||||
#########################################################################################
|
||||
run-binary-debug: $(sim_debug)
|
||||
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) $(WAVEFORM_FLAG) $(PERMISSIVE_OFF) $(BINARY) </dev/null 2> >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log)
|
||||
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(VERBOSE_FLAGS) $(WAVEFORM_FLAG) $(PERMISSIVE_OFF) $(BINARY) </dev/null 2> >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log)
|
||||
|
||||
run-fast: run-asm-tests-fast run-bmark-tests-fast
|
||||
|
||||
@@ -129,10 +140,10 @@ $(output_dir)/%: $(RISCV)/riscv64-unknown-elf/share/riscv-tests/isa/%
|
||||
ln -sf $< $@
|
||||
|
||||
$(output_dir)/%.run: $(output_dir)/% $(sim)
|
||||
(set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(PERMISSIVE_OFF) $< </dev/null | tee $<.log) && touch $@
|
||||
(set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(PERMISSIVE_OFF) $< </dev/null | tee $<.log) && touch $@
|
||||
|
||||
$(output_dir)/%.out: $(output_dir)/% $(sim)
|
||||
(set -o pipefail && $(sim) $(PERMISSIVE_ON) +dramsim +max-cycles=$(timeout_cycles) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $@) | tee $<.log)
|
||||
(set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $@) | tee $<.log)
|
||||
|
||||
#########################################################################################
|
||||
# include build/project specific makefrags made from the generator
|
||||
@@ -141,26 +152,6 @@ ifneq ($(filter run% %.run %.out %.vpd %.vcd,$(MAKECMDGOALS)),)
|
||||
-include $(build_dir)/$(long_name).d
|
||||
endif
|
||||
|
||||
#################################################
|
||||
# Rules for running and checking tracegen tests #
|
||||
#################################################
|
||||
|
||||
AXE_DIR=$(base_dir)/tools/axe/src
|
||||
AXE=$(AXE_DIR)/axe
|
||||
|
||||
$(AXE): $(wildcard $(AXE_DIR)/*.[ch]) $(AXE_DIR)/make.sh
|
||||
cd $(AXE_DIR) && ./make.sh
|
||||
|
||||
$(output_dir)/tracegen.out: $(sim)
|
||||
mkdir -p $(output_dir) && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) none </dev/null 2> $@
|
||||
|
||||
$(output_dir)/tracegen.result: $(output_dir)/tracegen.out $(AXE)
|
||||
$(base_dir)/scripts/check-tracegen.sh $< > $@
|
||||
|
||||
tracegen: $(output_dir)/tracegen.result
|
||||
|
||||
.PHONY: tracegen
|
||||
|
||||
#######################################
|
||||
# Rules for building DRAMSim2 library #
|
||||
#######################################
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<X>`` 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
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
----------------
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -38,6 +38,20 @@ Note that these configurations fully remove the L2 cache and mbus.
|
||||
This configuration fully removes the L2 cache and memory bus by setting the
|
||||
number of channels and number of banks to 0.
|
||||
|
||||
The System Bus
|
||||
--------------
|
||||
|
||||
The system bus is the TileLink network that sits between the tiles and the L2
|
||||
agents and MMIO peripherals. Ordinarily, it is a fully-connected crossbar,
|
||||
but TestChipIP provides a version that uses a ring network instead. This can
|
||||
be useful when taping out larger systems. To use the ring network system
|
||||
bus, simply add the ``WithRingSystemBus`` config fragment to your configuration.
|
||||
|
||||
.. literalinclude:: ../../generators/chipyard/src/main/scala/config/RocketConfigs.scala
|
||||
:language: scala
|
||||
:start-after: DOC include start: RingSystemBusRocket
|
||||
:end-before: DOC include end: RingSystemBusRocket
|
||||
|
||||
The SiFive L2 Cache
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ Configuration
|
||||
To add IceNIC to your design, add ``HasPeripheryIceNIC`` to your lazy module
|
||||
and ``HasPeripheryIceNICModuleImp`` to the module implementation. If you
|
||||
are confused about the distinction between lazy module and module
|
||||
implementation, refer to :ref:`Cake Pattern`.
|
||||
implementation, refer to :ref:`Cake Pattern / Mixin`.
|
||||
|
||||
Then add the ``WithIceNIC`` config fragment to your configuration. This will
|
||||
define ``NICKey``, which IceNIC uses to determine its parameters. The config fragment
|
||||
|
||||
@@ -3,7 +3,8 @@ Test Chip IP
|
||||
|
||||
Chipyard includes a Test Chip IP library which provides various hardware
|
||||
widgets that may be useful when designing SoCs. This includes a :ref:`Serial Adapter`,
|
||||
:ref:`Block Device Controller`, :ref:`TileLink SERDES`, :ref:`TileLink Switcher`, and :ref:`UART Adapter`.
|
||||
:ref:`Block Device Controller`, :ref:`TileLink SERDES`, :ref:`TileLink Switcher`,
|
||||
:ref:`TileLink Ring Network`, and :ref:`UART Adapter`.
|
||||
|
||||
Serial Adapter
|
||||
--------------
|
||||
@@ -60,6 +61,19 @@ the select signal once TileLink messages have begun sending.
|
||||
For an example of how to use the switcher, take a look at the ``SwitcherTest``
|
||||
unit test in the `Test Chip IP unit tests <https://github.com/ucb-bar/testchipip/blob/master/src/main/scala/Unittests.scala>`_.
|
||||
|
||||
TileLink Ring Network
|
||||
---------------------
|
||||
|
||||
TestChipIP provides a TLRingNetwork generator that has a similar interface
|
||||
to the TLXbar provided by RocketChip, but uses ring networks internally rather
|
||||
than crossbars. This can be useful for chips with very wide TileLink networks
|
||||
(many cores and L2 banks) that can sacrifice cross-section bandwidth to relieve
|
||||
wire routing congestion. Documentation on how to use the ring network can be
|
||||
found in :ref:`The System Bus`. The implementation itself can be found
|
||||
`here <https://github.com/ucb-bar/testchipip/blob/master/src/main/scala/Ring.scala>`_,
|
||||
and may serve as an example of how to implement your own TileLink network with
|
||||
a different topology.
|
||||
|
||||
UART Adapter
|
||||
------------
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS = -w warnings.txt
|
||||
SPHINXBUILD = python -msphinx
|
||||
SPHINXOPTS = -w warnings.txt -n -W
|
||||
SPHINXBUILD = python3 -msphinx
|
||||
SPHINXPROJ = Chipyard
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
@@ -169,7 +169,7 @@ transactions.
|
||||
- ``minSize: Int`` - Minimum size of transfers supported by all outward managers.
|
||||
- ``maxSize: Int`` - Maximum size of transfers supported after the Fragmenter is applied.
|
||||
- ``alwaysMin: Boolean`` - (optional) Fragment all requests down to minSize (else fragment to maximum supported by manager). (default: false)
|
||||
- ``earlyAck: EarlyAck.T`` - (optional) Should a multibeat Put be acknowledged on the first beat or last beat?
|
||||
- ``earlyAck: EarlyAck.T`` - (optional) Should a multibeat Put be acknowledged on the first beat or last beat?
|
||||
Possible values (default: ``EarlyAck.None``):
|
||||
|
||||
- ``EarlyAck.AllPuts`` - always acknowledge on first beat.
|
||||
@@ -270,7 +270,7 @@ the client to see a particular width.
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
.. code-block::
|
||||
.. code-block:: scala
|
||||
|
||||
// Assume the manager node sets beatBytes to 8
|
||||
// With WidthWidget, client sees beatBytes of 4
|
||||
@@ -398,11 +398,11 @@ package, not the ``freechips.rocketchip.tilelink`` package like the others.
|
||||
- ``size: Int`` - The size of the memory in bytes
|
||||
- ``contentsDelayed: => Seq[Byte]`` - A function which, when called generates
|
||||
the byte contents of the ROM.
|
||||
- ``executable: Boolean`` - (optional) Specify whether the CPU can fetch
|
||||
- ``executable: Boolean`` - (optional) Specify whether the CPU can fetch
|
||||
instructions from the ROM (default: ``true``).
|
||||
- ``beatBytes: Int`` - (optional) The width of the interface in bytes.
|
||||
- ``beatBytes: Int`` - (optional) The width of the interface in bytes.
|
||||
(default: 4).
|
||||
- ``resources: Seq[Resource]`` - (optional) Sequence of resources to add to
|
||||
- ``resources: Seq[Resource]`` - (optional) Sequence of resources to add to
|
||||
the device tree.
|
||||
|
||||
**Example Usage:**
|
||||
@@ -429,13 +429,13 @@ The TLRAM and AXI4RAM widgets provide read-write memories implemented as SRAMs.
|
||||
**Arguments:**
|
||||
|
||||
- ``address: AddressSet`` - The address range that this RAM will cover.
|
||||
- ``cacheable: Boolean`` - (optional) Can the contents of this RAM be cached.
|
||||
- ``cacheable: Boolean`` - (optional) Can the contents of this RAM be cached.
|
||||
(default: ``true``)
|
||||
- ``executable: Boolean`` - (optional) Can the contents of this RAM be fetched
|
||||
- ``executable: Boolean`` - (optional) Can the contents of this RAM be fetched
|
||||
as instructions. (default: ``true``)
|
||||
- ``beatBytes: Int`` - (optional) Width of the TL/AXI4 interface in bytes.
|
||||
- ``beatBytes: Int`` - (optional) Width of the TL/AXI4 interface in bytes.
|
||||
(default: 4)
|
||||
- ``atomics: Boolean`` - (optional, TileLink only) Does the RAM support
|
||||
- ``atomics: Boolean`` - (optional, TileLink only) Does the RAM support
|
||||
atomic operations? (default: ``false``)
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
@@ -131,5 +131,5 @@ This, unfortunately, breaks the process-agnostic RTL abstraction, so it is recom
|
||||
The simplest way to do this is to have a config fragment that when included updates instantiates the IO cells and connects them in the test harness.
|
||||
When simulating chip-specific designs, it is important to include the IO cells.
|
||||
The IO cell behavioral models will often assert if they are connected incorrectly, which is a useful runtime check.
|
||||
They also keep the IO interface at the chip and test harness boundary (see :ref:`Separating the top module from the test harness`) consistent after synthesis and place-and-route,
|
||||
They also keep the IO interface at the chip and test harness boundary (see :ref:`Separating the Top module from the TestHarness module`) consistent after synthesis and place-and-route,
|
||||
which allows the RTL simulation test harness to be reused.
|
||||
|
||||
@@ -45,8 +45,8 @@ It is possible to write this IR directly, or to generate it using simple python
|
||||
While we certainly look forward to having a more featureful toolkit, we have built many chips to date in this way.
|
||||
|
||||
|
||||
Running the VLSI flow
|
||||
---------------------
|
||||
Running the VLSI tool flow
|
||||
--------------------------
|
||||
|
||||
For the full documentation on how to use the VLSI tool flow, see the `Hammer Documentation <https://hammer-vlsi.readthedocs.io/>`__.
|
||||
For an example of how to use the VLSI in the context of Chipyard, see :ref:`ASAP7 Tutorial`.
|
||||
|
||||
Submodule generators/ariane updated: 145b5ed106...e02436d2aa
102
generators/chipyard/src/main/scala/ChipTop.scala
Normal file
102
generators/chipyard/src/main/scala/ChipTop.scala
Normal file
@@ -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
|
||||
@@ -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"))
|
||||
})
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -364,6 +364,7 @@ class ScratchpadRocketConfig extends Config(
|
||||
new freechips.rocketchip.system.BaseConfig)
|
||||
// DOC include end: scratchpadrocket
|
||||
|
||||
// DOC include start: RingSystemBusRocket
|
||||
class RingSystemBusRocketConfig extends Config(
|
||||
new chipyard.iobinders.WithUARTAdapter ++
|
||||
new chipyard.iobinders.WithTieOffInterrupts ++
|
||||
@@ -382,3 +383,4 @@ class RingSystemBusRocketConfig extends Config(
|
||||
new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
|
||||
new freechips.rocketchip.system.BaseConfig)
|
||||
// DOC include end: RingSystemBusRocket
|
||||
|
||||
@@ -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 ++
|
||||
|
||||
@@ -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
|
||||
@@ -30,75 +31,63 @@ import chipyard.HasChipyardTilesModuleImp
|
||||
|
||||
object MainMemoryConsts {
|
||||
val regionNamePrefix = "MainMemory"
|
||||
def globalName(): String = s"${regionNamePrefix}_${NodeIdx()}"
|
||||
def globalName = s"${regionNamePrefix}_${NodeIdx()}"
|
||||
}
|
||||
|
||||
class WithSerialBridge extends OverrideIOBinder({
|
||||
(c, r, s, target: CanHavePeripherySerialModuleImp) =>
|
||||
target.serial.map(s => SerialBridge(target.clock, s, MainMemoryConsts.globalName)(target.p)).toSeq
|
||||
(system: CanHavePeripherySerialModuleImp) =>
|
||||
system.serial.foreach(s => SerialBridge(system.clock, s, MainMemoryConsts.globalName)(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
|
||||
})
|
||||
|
||||
// Assign a unique name to each target memory space, consisting of one or more
|
||||
// memory channels. In the multi-node case, serial widgets can then disambiguate
|
||||
// each memory region using this string instead of relying on the assumption
|
||||
// the target has a single memory channel.
|
||||
object MemoryRegionNames {
|
||||
var idx = -1
|
||||
def getName(): String = {
|
||||
idx += 1
|
||||
s"memory_${idx}"
|
||||
}
|
||||
}
|
||||
|
||||
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) =>
|
||||
class WithFASEDBridge extends OverrideIOBinder({
|
||||
(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)),
|
||||
Some(MainMemoryConsts.globalName)))
|
||||
})
|
||||
}).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)))
|
||||
@@ -120,13 +109,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 ++
|
||||
|
||||
@@ -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.
|
||||
@@ -34,14 +34,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))
|
||||
for ((target) <- targets) {
|
||||
p(IOBinders).values.map(_(target))
|
||||
NodeIdx.increment()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Submodule generators/icenet updated: f227228474...b1f957e6eb
Submodule generators/testchipip updated: 30d44252e8...d06d7c7dc2
18
generators/tracegen/tracegen.mk
Normal file
18
generators/tracegen/tracegen.mk
Normal file
@@ -0,0 +1,18 @@
|
||||
##############################################################
|
||||
# extra variables/targets ingested by the chipyard make system
|
||||
##############################################################
|
||||
|
||||
AXE_DIR=$(base_dir)/tools/axe/src
|
||||
AXE=$(AXE_DIR)/axe
|
||||
|
||||
$(AXE): $(wildcard $(AXE_DIR)/*.[ch]) $(AXE_DIR)/make.sh
|
||||
cd $(AXE_DIR) && ./make.sh
|
||||
|
||||
$(output_dir)/tracegen.out: $(sim)
|
||||
mkdir -p $(output_dir) && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) none </dev/null 2> $@
|
||||
|
||||
$(output_dir)/tracegen.result: $(output_dir)/tracegen.out $(AXE)
|
||||
$(base_dir)/scripts/check-tracegen.sh $< > $@
|
||||
|
||||
.PHONY: tracegen
|
||||
tracegen: $(output_dir)/tracegen.result
|
||||
@@ -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)
|
||||
|
||||
Submodule sims/firesim updated: 998eeaea23...a4f0a18c0a
@@ -50,7 +50,8 @@ VCS_CC_OPTS = \
|
||||
-CC "-I$(dramsim_dir)" \
|
||||
-CC "-std=c++11" \
|
||||
$(dramsim_lib) \
|
||||
$(RISCV)/lib/libfesvr.a
|
||||
$(RISCV)/lib/libfesvr.a \
|
||||
-CC "$(EXTRA_SIM_CC_FLAGS)"
|
||||
|
||||
VCS_NONCC_OPTS = \
|
||||
+lint=all,noVCDE,noONGS,noUI \
|
||||
@@ -80,16 +81,16 @@ VCS_DEFINES = \
|
||||
+define+RANDOMIZE_GARBAGE_ASSIGN \
|
||||
+define+RANDOMIZE_INVALID_ASSIGN
|
||||
|
||||
VCS_OPTS = -notice -line $(VCS_CC_OPTS) $(VCS_NONCC_OPTS) $(VCS_DEFINES)
|
||||
VCS_OPTS = -notice -line $(VCS_CC_OPTS) $(VCS_NONCC_OPTS) $(VCS_DEFINES) $(EXTRA_SIM_SOURCES)
|
||||
|
||||
#########################################################################################
|
||||
# vcs simulator rules
|
||||
#########################################################################################
|
||||
$(sim): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib)
|
||||
$(sim): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS)
|
||||
rm -rf csrc && $(VCS) $(VCS_OPTS) -o $@ \
|
||||
-debug_pp
|
||||
|
||||
$(sim_debug): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib)
|
||||
$(sim_debug): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS)
|
||||
rm -rf csrc && $(VCS) $(VCS_OPTS) -o $@ \
|
||||
+define+DEBUG \
|
||||
-debug_pp
|
||||
@@ -99,7 +100,7 @@ $(sim_debug): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib)
|
||||
#########################################################################################
|
||||
.PRECIOUS: $(output_dir)/%.vpd %.vpd
|
||||
$(output_dir)/%.vpd: $(output_dir)/% $(sim_debug)
|
||||
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $<.out) | tee $<.log)
|
||||
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $<.out) | tee $<.log)
|
||||
|
||||
#########################################################################################
|
||||
# general cleanup rule
|
||||
|
||||
@@ -47,14 +47,25 @@ include $(base_dir)/common.mk
|
||||
#########################################################################################
|
||||
VERILATOR := verilator --cc --exe
|
||||
|
||||
CXXFLAGS := $(CXXFLAGS) -O1 -std=c++11 -I$(RISCV)/include -I$(dramsim_dir) -D__STDC_FORMAT_MACROS
|
||||
LDFLAGS := $(LDFLAGS) -L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib -L$(dramsim_dir) -Wl,-rpath,$(dramsim_dir) -L$(sim_dir) -lfesvr -lpthread -ldramsim
|
||||
CXXFLAGS := \
|
||||
$(CXXFLAGS) -O1 -std=c++11 \
|
||||
-I$(RISCV)/include \
|
||||
-I$(dramsim_dir) \
|
||||
-D__STDC_FORMAT_MACROS \
|
||||
$(EXTRA_SIM_CC_FLAGS)
|
||||
|
||||
LDFLAGS := \
|
||||
$(LDFLAGS) \
|
||||
-L$(sim_dir) \
|
||||
-lpthread
|
||||
|
||||
VERILATOR_CC_OPTS = \
|
||||
-O3 \
|
||||
-CFLAGS "$(CXXFLAGS) -DTEST_HARNESS=V$(VLOG_MODEL) -DVERILATOR" \
|
||||
-CFLAGS "-I$(build_dir) -include $(build_dir)/$(long_name).plusArgs -include $(build_dir)/verilator.h" \
|
||||
-LDFLAGS "$(LDFLAGS)"
|
||||
-LDFLAGS "$(LDFLAGS)" \
|
||||
$(RISCV)/lib/libfesvr.a \
|
||||
$(dramsim_lib)
|
||||
|
||||
# default flags added for ariane
|
||||
ARIANE_VERILATOR_FLAGS = \
|
||||
@@ -87,7 +98,7 @@ VERILATOR_DEFINES = \
|
||||
+define+PRINTF_COND=\$$c\(\"verbose\",\"\&\&\"\,\"done_reset\"\) \
|
||||
+define+STOP_COND=\$$c\(\"done_reset\"\)
|
||||
|
||||
VERILATOR_OPTS = $(VERILATOR_CC_OPTS) $(VERILATOR_NONCC_OPTS) $(VERILATOR_DEFINES)
|
||||
VERILATOR_OPTS = $(VERILATOR_CC_OPTS) $(VERILATOR_NONCC_OPTS) $(VERILATOR_DEFINES) $(EXTRA_SIM_SOURCES)
|
||||
|
||||
#########################################################################################
|
||||
# verilator build paths and file names
|
||||
@@ -104,13 +115,13 @@ model_mk_debug = $(model_dir_debug)/V$(VLOG_MODEL).mk
|
||||
#########################################################################################
|
||||
# build makefile fragment that builds the verilator sim rules
|
||||
#########################################################################################
|
||||
$(model_mk): $(sim_vsrcs) $(sim_common_files)
|
||||
$(model_mk): $(sim_vsrcs) $(sim_common_files) $(EXTRA_SIM_REQS)
|
||||
rm -rf $(build_dir)/$(long_name)
|
||||
mkdir -p $(build_dir)/$(long_name)
|
||||
$(VERILATOR) $(VERILATOR_OPTS) -o $(sim) -Mdir $(model_dir) -CFLAGS "-include $(model_header)"
|
||||
touch $@
|
||||
|
||||
$(model_mk_debug): $(sim_vsrcs) $(sim_common_files)
|
||||
$(model_mk_debug): $(sim_vsrcs) $(sim_common_files) $(EXTRA_SIM_REQS)
|
||||
rm -rf $(build_dir)/$(long_name)
|
||||
mkdir -p $(build_dir)/$(long_name).debug
|
||||
$(VERILATOR) $(VERILATOR_OPTS) -o $(sim_debug) --trace -Mdir $(model_dir_debug) -CFLAGS "-include $(model_header_debug)"
|
||||
@@ -132,7 +143,7 @@ $(sim_debug): $(model_mk_debug) $(dramsim_lib)
|
||||
$(output_dir)/%.vpd: $(output_dir)/% $(sim_debug)
|
||||
rm -f $@.vcd && mkfifo $@.vcd
|
||||
vcd2vpd $@.vcd $@ > /dev/null &
|
||||
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) -v$@.vcd $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $<.out) | tee $<.log)
|
||||
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(VERBOSE_FLAGS) -v$@.vcd $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $<.out) | tee $<.log)
|
||||
|
||||
#########################################################################################
|
||||
# general cleanup rule
|
||||
|
||||
Submodule software/spec2017 updated: b864313643...a4333f243c
Submodule tools/barstools updated: 63d74bc177...db6776367c
@@ -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)
|
||||
@@ -143,7 +143,7 @@ output_dir=$(sim_dir)/output/$(long_name)
|
||||
# helper variables to run binaries
|
||||
#########################################################################################
|
||||
BINARY ?=
|
||||
SIM_FLAGS ?=
|
||||
override SIM_FLAGS += +dramsim +max-cycles=$(timeout_cycles)
|
||||
VERBOSE_FLAGS ?= +verbose
|
||||
sim_out_name = $(subst $() $(),_,$(notdir $(basename $(BINARY))).$(long_name))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user