Merge branch 'dev' of github.com:ucb-bar/chipyard into sodor-integrate

This commit is contained in:
Zitao Fang
2020-09-06 23:09:50 -07:00
56 changed files with 1071 additions and 570 deletions

View File

@@ -82,7 +82,12 @@ search
submodules=("coremark" "firemarshal" "nvdla-workload" "spec2017")
dir="software"
branches=("master")
if [ "$CIRCLE_BRANCH" == "master" ] || [ "$CIRCLE_BRANCH" == "dev" ]
then
branches=("master")
else
branches=("master" "dev")
fi
search
submodules=("DRAMSim2" "axe" "barstools" "chisel-testers" "dsptools" "firrtl-interpreter" "torture" "treadle")

View File

@@ -6,7 +6,7 @@ version: 2.1
parameters:
tools-cache-version:
type: string
default: "v5"
default: "v6"
# default execution env.s
executors:
@@ -199,6 +199,11 @@ jobs:
steps:
- prepare-rtl:
project-key: "chipyard-rocket"
prepare-chipyard-dmirocket:
executor: main-env
steps:
- prepare-rtl:
project-key: "chipyard-dmirocket"
prepare-chipyard-sha3:
executor: main-env
steps:
@@ -225,11 +230,6 @@ jobs:
steps:
- prepare-rtl:
project-key: "chipyard-boom"
prepare-rocketchip:
executor: main-env
steps:
- prepare-rtl:
project-key: "rocketchip"
prepare-chipyard-blkdev:
executor: main-env
steps:
@@ -297,6 +297,11 @@ jobs:
steps:
- run-tests:
project-key: "chipyard-rocket"
chipyard-dmirocket-run-tests:
executor: main-env
steps:
- run-tests:
project-key: "chipyard-dmirocket"
chipyard-sha3-run-tests:
executor: main-env
steps:
@@ -323,11 +328,6 @@ jobs:
steps:
- run-tests:
project-key: "chipyard-boom"
rocketchip-run-tests:
executor: main-env
steps:
- run-tests:
project-key: "rocketchip"
chipyard-hwacha-run-tests:
executor: main-env
steps:
@@ -451,6 +451,11 @@ workflows:
- install-riscv-toolchain
- install-verilator
- prepare-chipyard-dmirocket:
requires:
- install-riscv-toolchain
- install-verilator
- prepare-chipyard-sha3:
requires:
- install-riscv-toolchain
@@ -476,11 +481,6 @@ workflows:
- install-riscv-toolchain
- install-verilator
- prepare-rocketchip:
requires:
- install-riscv-toolchain
- install-verilator
- prepare-chipyard-blkdev:
requires:
- install-riscv-toolchain
@@ -547,6 +547,10 @@ workflows:
requires:
- prepare-chipyard-rocket
- chipyard-dmirocket-run-tests:
requires:
- prepare-chipyard-dmirocket
- chipyard-sha3-run-tests:
requires:
- prepare-chipyard-sha3
@@ -567,10 +571,6 @@ workflows:
requires:
- prepare-chipyard-boom
- rocketchip-run-tests:
requires:
- prepare-rocketchip
- chipyard-hwacha-run-tests:
requires:
- prepare-chipyard-hwacha

View File

@@ -48,6 +48,7 @@ LOCAL_FIRESIM_DIR=$LOCAL_CHIPYARD_DIR/sims/firesim/sim
# key value store to get the build strings
declare -A mapping
mapping["chipyard-rocket"]=""
mapping["chipyard-dmirocket"]=" CONFIG=dmiRocketConfig"
mapping["chipyard-sha3"]=" CONFIG=Sha3RocketConfig"
mapping["chipyard-streaming-fir"]=" CONFIG=StreamingFIRRocketConfig"
mapping["chipyard-streaming-passthrough"]=" CONFIG=StreamingPassthroughRocketConfig"

View File

@@ -59,7 +59,7 @@ run "export RISCV=\"$TOOLS_DIR\"; \
export VERILATOR_ROOT=\"$REMOTE_VERILATOR_DIR\"; \
export COURSIER_CACHE=\"$REMOTE_WORK_DIR/.coursier-cache\"; \
make -C $REMOTE_SIM_DIR clean; \
make -j$REMOTE_MAKE_NPROC -C $REMOTE_SIM_DIR JAVA_ARGS=\"$REMOTE_JAVA_ARGS\" ${mapping[$1]}"
make -j$REMOTE_MAKE_NPROC -C $REMOTE_SIM_DIR FIRRTL_LOGLEVEL=info JAVA_ARGS=\"$REMOTE_JAVA_ARGS\" ${mapping[$1]}"
run "rm -rf $REMOTE_CHIPYARD_DIR/project"
# copy back the final build

View File

@@ -32,6 +32,9 @@ case $1 in
chipyard-rocket)
run_bmark ${mapping[$1]}
;;
chipyard-dmirocket)
run_bmark ${mapping[$1]}
;;
chipyard-boom)
run_bmark ${mapping[$1]}
;;

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ target
*.stamp
*.vcd
*.swp
*.swo
*.log
*#
*~

View File

@@ -3,22 +3,49 @@
#########################################################################################
SHELL=/bin/bash
ifndef RISCV
$(error RISCV is unset. You must set RISCV yourself, or through the Chipyard auto-generated env file)
else
$(info Running with RISCV=$(RISCV))
endif
#########################################################################################
# specify user-interface variables
#########################################################################################
HELP_COMPILATION_VARIABLES += \
" EXTRA_GENERATOR_REQS = additional make requirements needed for the main generator" \
" EXTRA_SIM_CXXFLAGS = additional CXXFLAGS for building simulators" \
" EXTRA_SIM_LDFLAGS = additional LDFLAGS for building simulators" \
" EXTRA_SIM_SOURCES = additional simulation sources needed for simulator" \
" EXTRA_SIM_REQS = additional make requirements to build the simulator"
EXTRA_GENERATOR_REQS ?=
EXTRA_SIM_CXXFLAGS ?=
EXTRA_SIM_LDFLAGS ?=
EXTRA_SIM_SOURCES ?=
EXTRA_SIM_REQS ?=
#----------------------------------------------------------------------------
HELP_SIMULATION_VARIABLES += \
" EXTRA_SIM_FLAGS = additional runtime simulation flags (passed within +permissive)" \
" NUMACTL = set to '1' to wrap simulator in the appropriate numactl command"
EXTRA_SIM_FLAGS ?=
NUMACTL ?= 0
NUMA_PREFIX = $(if $(filter $(NUMACTL),0),,$(shell $(base_dir)/scripts/numa_prefix))
#----------------------------------------------------------------------------
HELP_COMMANDS += \
" run-binary = run [./$(shell basename $(sim))] and log instructions to file" \
" run-binary-fast = run [./$(shell basename $(sim))] and don't log instructions" \
" run-binary-debug = run [./$(shell basename $(sim_debug))] and log instructions and waveform to files" \
" verilog = generate intermediate verilog files from chisel elaboration and firrtl passes" \
" run-tests = run all assembly and benchmark tests"
#########################################################################################
# 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 additional subproject make fragments
# see HELP_COMPILATION_VARIABLES
#########################################################################################
include $(base_dir)/generators/ariane/ariane.mk
include $(base_dir)/generators/tracegen/tracegen.mk
@@ -35,7 +62,8 @@ SOURCE_DIRS = $(addprefix $(base_dir)/,generators sims/firesim/sim tools/barstoo
SCALA_SOURCES = $(call lookup_srcs,$(SOURCE_DIRS),scala)
VLOG_SOURCES = $(call lookup_srcs,$(SOURCE_DIRS),sv) $(call lookup_srcs,$(SOURCE_DIRS),v)
# This assumes no SBT meta-build sources
SBT_SOURCES = $(call lookup_srcs,$(base_dir),sbt)
SBT_SOURCE_DIRS = $(addprefix $(base_dir)/,generators sims/firesim/sim tools)
SBT_SOURCES = $(call lookup_srcs,$(SBT_SOURCE_DIRS),sbt) $(base_dir)/build.sbt $(base_dir)/project/plugins.sbt
#########################################################################################
# jar creation variables and rules
@@ -55,7 +83,6 @@ $(FIRRTL_TEST_JAR): $(call lookup_srcs,$(CHIPYARD_FIRRTL_DIR),scala)
cp -p $(CHIPYARD_FIRRTL_DIR)/utils/bin/firrtl-test.jar $@
touch $@
#########################################################################################
# Bloop Project Definitions
#########################################################################################
@@ -140,20 +167,18 @@ verilog: $(sim_vsrcs)
# helper rules to run simulations
#########################################################################################
.PHONY: run-binary run-binary-fast run-binary-debug run-fast
# run normal binary with hardware-logged insn dissassembly
run-binary: $(output_dir) $(sim)
(set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $(BINARY) </dev/null 2> >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log)
(set -o pipefail && $(NUMA_PREFIX) $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(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 simulator as fast as possible (no insn disassembly)
run-binary-fast: $(output_dir) $(sim)
(set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(PERMISSIVE_OFF) $(BINARY) </dev/null | tee $(sim_out_name).log)
(set -o pipefail && $(NUMA_PREFIX) $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(PERMISSIVE_OFF) $(BINARY) </dev/null | tee $(sim_out_name).log)
#########################################################################################
# helper rules to run simulator with as much debug info as possible
#########################################################################################
# run simulator with as much debug info as possible
run-binary-debug: $(output_dir) $(sim_debug)
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) $(WAVEFORM_FLAG) $(PERMISSIVE_OFF) $(BINARY) </dev/null 2> >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log)
(set -o pipefail && $(NUMA_PREFIX) $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(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
@@ -189,10 +214,10 @@ $(output_dir)/%: $(RISCV)/riscv64-unknown-elf/share/riscv-tests/isa/% $(output_d
ln -sf $< $@
$(output_dir)/%.run: $(output_dir)/% $(sim)
(set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(PERMISSIVE_OFF) $< </dev/null | tee $<.log) && touch $@
(set -o pipefail && $(NUMA_PREFIX) $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(PERMISSIVE_OFF) $< </dev/null | tee $<.log) && touch $@
$(output_dir)/%.out: $(output_dir)/% $(sim)
(set -o pipefail && $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $@) | tee $<.log)
(set -o pipefail && $(NUMA_PREFIX) $(sim) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $@) | tee $<.log)
#########################################################################################
# include build/project specific makefrags made from the generator
@@ -211,6 +236,13 @@ dramsim_lib = $(dramsim_dir)/libdramsim.a
$(dramsim_lib):
$(MAKE) -C $(dramsim_dir) $(notdir $@)
#########################################################################################
# print help text
#########################################################################################
.PHONY: help
help:
@for line in $(HELP_LINES); do echo "$$line"; done
#########################################################################################
# Implicit rule handling
#########################################################################################

View File

@@ -130,38 +130,8 @@ Using the JTAG Interface
------------------------
The main way to use JTAG with a Rocket Chip based system is to instantiate the Debug Transfer Module (DTM)
and configure it to use a JTAG interface (by default the DTM is setup to use the DMI interface mentioned above).
Creating a DTM+JTAG Config
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
First, a DTM config must be created for the system that you want to create.
This step is similar to the DMI simulation section within the :ref:`Starting the TSI or DMI Simulation` section.
The configuration is very similar to a DMI-based configuration. The main difference
is the addition of the ``WithJtagDTM`` config fragment that configures the instantiated DTM to use the JTAG protocol as the
bringup method.
.. literalinclude:: ../../generators/chipyard/src/main/scala/config/RocketConfigs.scala
:language: scala
:start-after: DOC include start: JtagRocket
:end-before: DOC include end: JtagRocket
Building a DTM+JTAG Simulator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After creating the config, call the ``make`` command like the following to build a simulator for your RTL:
.. code-block:: bash
cd sims/verilator
# or
cd sims/vcs
make CONFIG=jtagRocketConfig
In this example, the simulation will use the config that you previously specified, as well as set
the other parameters that are needed to satisfy the build system. After that point, you
should have a JTAG enabled simulator that you can attach to using OpenOCD and GDB!
and configure it to use a JTAG interface. The default Chipyard designs instantiate the DTM and configure it
to use JTAG. You may attach OpenOCD and GDB to any of the default JTAG-enabled designs.
Debugging with JTAG
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -40,8 +40,7 @@ For a proprietry VCS simulation, enter the ``sims/vcs`` directory
# Enter VCS directory
cd sims/vcs
.. _sim-default:
.. _sw-sim-help:
Simulating The Default Example
-------------------------------
@@ -82,6 +81,22 @@ For example:
.. _sw-sim-custom:
Makefile Variables and Commands
-------------------------------
You can get a list of useful Makefile variables and commands available from the Verilator or VCS directories. simply run ``make help``:
.. code-block:: shell
# Enter Verilator directory
cd sims/verilator
make help
# Enter VCS directory
cd sims/vcs
make help
.. _sim-default:
Simulating A Custom Project
-------------------------------
@@ -167,3 +182,18 @@ An open-source vcd-capable waveform viewer is `GTKWave <http://gtkwave.sourcefor
For a VCS simulation, this will generate a vpd file (this is a proprietary waveform representation format used by Synopsys) that can be loaded to vpd-supported waveform viewers.
If you have Synopsys licenses, we recommend using the DVE waveform viewer.
.. _sw-sim-verilator-opts:
Additional Verilator Options
-------------------------------
When building the verilator simulator there are some additional options:
.. code-block:: shell
make VERILATOR_THREADS=8 NUMACTL=1
The ``VERILATOR_THREADS=<num>`` option enables the compiled Verilator simulator to use ``<num>`` parallel threads.
On a multi-socket machine, you will want to make sure all threads are on the same socket by using ``NUMACTL=1`` to enable ``numactl``.
By enabling this, you will use Chipyard's ``numa_prefix`` wrapper, which is a simple wrapper around ``numactl`` that runs your verilated simulator like this: ``$(numa_prefix) ./simulator-<name> <simulator-args>``.
Note that both these flags are mutually exclusive, you can use either independently (though it makes sense to use ``NUMACTL`` just with ``VERILATOR_THREADS=8`` during a Verilator simulation).

View File

@@ -4,118 +4,64 @@ import chisel3._
import scala.collection.mutable.{ArrayBuffer}
import freechips.rocketchip.prci.{ClockGroupIdentityNode, ClockSinkParameters, ClockSinkNode, ClockGroup}
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey}
import freechips.rocketchip.config.{Parameters, Field}
import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, LazyRawModuleImp, LazyModuleImpLike}
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 => LazyModule]((p: Parameters) => LazyModule(new DigitalTop()(p)))
/**
* Chipyard provides three baseline, top-level reset schemes, set using the
* [[GlobalResetSchemeKey]] in a Parameters instance. These are:
*
* 1) Synchronous: The input coming to the chip is synchronous to the provided
* clocks and will be used without modification as a synchronous reset.
* This is safe only for use in FireSim and SW simulation.
*
* 2) Asynchronous: The input reset is asynchronous to the input clock, but it
* is caught and synchronized to that clock before it is dissemenated.
* Thus, downsteam modules will be emitted with synchronously reset state
* elements.
*
* 3) Asynchronous Full: The input reset is asynchronous to the input clock,
* and is used globally as an async reset. Downstream modules will be emitted
* with asynchronously reset state elements.
*
*/
sealed trait GlobalResetScheme {
def pinIsAsync: Boolean
}
sealed trait HasAsyncInput { self: GlobalResetScheme =>
def pinIsAsync = true
}
sealed trait HasSyncInput { self: GlobalResetScheme =>
def pinIsAsync = false
}
case object GlobalResetSynchronous extends GlobalResetScheme with HasSyncInput
case object GlobalResetAsynchronous extends GlobalResetScheme with HasAsyncInput
case object GlobalResetAsynchronousFull extends GlobalResetScheme with HasAsyncInput
case object GlobalResetSchemeKey extends Field[GlobalResetScheme](GlobalResetSynchronous)
case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) => new DigitalTop()(p))
/**
* 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.
* named "system", which is an instance of DigitalTop by default. The diplomatic clocks of System, as well as its implicit clock,
* is aggregated into the clockGroupNode. The parameterized functions controlled by ClockingSchemeKey and GlobalResetSchemeKey
* drive clock and reset generation
*/
abstract class BaseChipTop()(implicit val p: Parameters) extends RawModule with HasTestHarnessFunctions {
class ChipTop(implicit p: Parameters) extends LazyModule 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
// These are given so that IOCell can use DataMirror and generate ports with
// the right flow (Input/Output)
val systemClock = Wire(Input(Clock()))
val systemReset = Wire(Input(Reset()))
// The system module specified by BuildSystem
val lSystem = p(BuildSystem)(p).suggestName("system")
val system = withClockAndReset(systemClock, systemReset) { Module(lSystem.module) }
val lSystem = LazyModule(p(BuildSystem)(p)).suggestName("system")
// Call all of the IOBinders and provide them with a default clock and reset
withClockAndReset(systemClock, systemReset) {
// Call each IOBinder on both the lazyModule instance and the module
// instance. Generally, an IOBinder PF should only be defined on one, so
// this should not lead to two invocations.
val (_ports, _iocells, _harnessFunctions) = p(IOBinders).values.flatMap(f => f(lSystem) ++ f(system)).unzip3
// We ignore _ports for now...
iocells ++= _iocells.flatten
harnessFunctions ++= _harnessFunctions.flatten
// The implicitClockSinkNode provides the implicit clock and reset for the System
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters()))
// Generate Clocks and Reset
p(ClockingSchemeKey)(this)
// NOTE: Making this a LazyRawModule is moderately dangerous, as anonymous children
// of ChipTop (ex: ClockGroup) do not receive clock or reset.
// However. anonymous children of ChipTop should not need an implicit Clock or Reset
// anyways, they probably need to be explicitly clocked.
lazy val module: LazyModuleImpLike = new LazyRawModuleImp(this) {
// These become the implicit clock and reset to the System
val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset
// The implicit clock and reset for the system is also, by convention, used for all the IOBinders
// TODO: This may not be the right thing to do in all cases
withClockAndReset(implicit_clock, implicit_reset) {
val (_ports, _iocells, _harnessFunctions) = p(IOBinders).values.flatMap(f => f(lSystem) ++ f(lSystem.module)).unzip3
// We ignore _ports for now...
iocells ++= _iocells.flatten
harnessFunctions ++= _harnessFunctions.flatten
}
// Connect the implicit clock/reset, if present
lSystem.module match { case l: LazyModuleImp => {
l.clock := implicit_clock
l.reset := implicit_reset
}}
}
}
/**
* 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. Three basic reset schemes
* are provided. See [[GlobalResetScheme]].
*/
trait HasChipTopSimpleClockAndReset { this: BaseChipTop =>
val (clock, systemClockIO) = IOCell.generateIOFromSignal(systemClock, Some("iocell_clock"))
val (reset, systemResetIO) = p(GlobalResetSchemeKey) match {
case GlobalResetSynchronous =>
IOCell.generateIOFromSignal(systemReset, Some("iocell_reset"))
case GlobalResetAsynchronousFull =>
IOCell.generateIOFromSignal(systemReset, Some("iocell_reset"), abstractResetAsAsync = true)
case GlobalResetAsynchronous =>
val asyncResetCore = Wire(Input(AsyncReset()))
systemReset := ResetCatchAndSync(systemClock, asyncResetCore.asBool)
IOCell.generateIOFromSignal(asyncResetCore, Some("iocell_reset"), abstractResetAsAsync = true)
}
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
} }
}
class ChipTop()(implicit p: Parameters) extends BaseChipTop()(p)
with HasChipTopSimpleClockAndReset

View File

@@ -0,0 +1,178 @@
package chipyard
import chisel3._
import scala.collection.mutable.{ArrayBuffer}
import freechips.rocketchip.prci._
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey}
import freechips.rocketchip.config.{Parameters, Field}
import freechips.rocketchip.diplomacy.{OutwardNodeHandle, InModuleBody, LazyModule}
import freechips.rocketchip.util.{ResetCatchAndSync, Pow2ClockDivider}
import barstools.iocell.chisel._
/**
* Chipyard provides three baseline, top-level reset schemes, set using the
* [[GlobalResetSchemeKey]] in a Parameters instance. These are:
*
* 1) Synchronous: The input coming to the chip is synchronous to the provided
* clocks and will be used without modification as a synchronous reset.
* This is safe only for use in FireSim and SW simulation.
*
* 2) Asynchronous: The input reset is asynchronous to the input clock, but it
* is caught and synchronized to that clock before it is dissemenated.
* Thus, downsteam modules will be emitted with synchronously reset state
* elements.
*
* 3) Asynchronous Full: The input reset is asynchronous to the input clock,
* and is used globally as an async reset. Downstream modules will be emitted
* with asynchronously reset state elements.
*
*/
sealed trait GlobalResetScheme {
def pinIsAsync: Boolean
}
sealed trait HasAsyncInput { self: GlobalResetScheme =>
def pinIsAsync = true
}
sealed trait HasSyncInput { self: GlobalResetScheme =>
def pinIsAsync = false
}
case object GlobalResetSynchronous extends GlobalResetScheme with HasSyncInput
case object GlobalResetAsynchronous extends GlobalResetScheme with HasAsyncInput
case object GlobalResetAsynchronousFull extends GlobalResetScheme with HasAsyncInput
case object GlobalResetSchemeKey extends Field[GlobalResetScheme](GlobalResetSynchronous)
/**
* A simple reset implementation that punches out reset ports
* for standard Module classes. Three basic reset schemes
* are provided. See [[GlobalResetScheme]].
*/
object GenerateReset {
def apply(chiptop: ChipTop, clock: Clock): Reset = {
implicit val p = chiptop.p
// this needs directionality so generateIOFromSignal works
val reset_wire = Wire(Input(Reset()))
val (reset_io, resetIOCell) = p(GlobalResetSchemeKey) match {
case GlobalResetSynchronous =>
IOCell.generateIOFromSignal(reset_wire, Some("iocell_reset"))
case GlobalResetAsynchronousFull =>
IOCell.generateIOFromSignal(reset_wire, Some("iocell_reset"), abstractResetAsAsync = true)
case GlobalResetAsynchronous => {
val async_reset_wire = Wire(Input(AsyncReset()))
reset_wire := ResetCatchAndSync(clock, async_reset_wire.asBool())
IOCell.generateIOFromSignal(async_reset_wire, Some("iocell_reset"), abstractResetAsAsync = true)
}
}
reset_io.suggestName("reset")
chiptop.iocells ++= resetIOCell
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
reset_io := th.dutReset
Nil
})
reset_wire
}
}
case object ClockingSchemeKey extends Field[ChipTop => Unit](ClockingSchemeGenerators.harnessClock)
object ClockingSchemeGenerators {
// A simple clock provider, for testing
val harnessClock: ChipTop => Unit = { chiptop =>
implicit val p = chiptop.p
val implicitClockSourceNode = ClockSourceNode(Seq(ClockSourceParameters()))
chiptop.implicitClockSinkNode := implicitClockSourceNode
// Drive the diplomaticclock graph of the DigitalTop (if present)
val simpleClockGroupSourceNode = chiptop.lSystem match {
case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => {
val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
l.asyncClockGroupsNode := n
Some(n)
}
case _ => None
}
InModuleBody {
//this needs directionality so generateIOFromSignal works
val clock_wire = Wire(Input(Clock()))
val reset_wire = GenerateReset(chiptop, clock_wire)
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, Some("iocell_clock"))
chiptop.iocells ++= clockIOCell
clock_io.suggestName("clock")
implicitClockSourceNode.out.unzip._1.map { o =>
o.clock := clock_wire
o.reset := reset_wire
}
simpleClockGroupSourceNode.map { n => n.out.unzip._1.map { out: ClockGroupBundle =>
out.member.data.foreach { o =>
o.clock := clock_wire
o.reset := reset_wire
}
}}
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
clock_io := th.harnessClock
Nil
})
}
}
val harnessDividedClock: ChipTop => Unit = { chiptop =>
implicit val p = chiptop.p
require(false, "Divided clock is broken until we fix passing onchip clocks to TestHarness objects")
val implicitClockSourceNode = ClockSourceNode(Seq(ClockSourceParameters()))
chiptop.implicitClockSinkNode := implicitClockSourceNode
val simpleClockGroupSourceNode = chiptop.lSystem match {
case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => {
val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
l.asyncClockGroupsNode := n
Some(n)
}
case _ => throw new Exception("Harness multiclock assumes BaseSubsystem")
}
InModuleBody {
// this needs directionality so generateIOFromSignal works
val clock_wire = Wire(Input(Clock()))
val reset_wire = GenerateReset(chiptop, clock_wire)
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, Some("iocell_clock"))
chiptop.iocells ++= clockIOCell
clock_io.suggestName("clock")
val div_clock = Pow2ClockDivider(clock_wire, 2)
implicitClockSourceNode.out.unzip._1.map { o =>
o.clock := div_clock
o.reset := reset_wire
}
simpleClockGroupSourceNode.map { n => n.out.unzip._1.map { out: ClockGroupBundle =>
out.member.elements.map { case (name, data) =>
// This is mega hacks, how are you actually supposed to do this?
data.clock := (if (name.contains("core")) clock_wire else div_clock)
data.reset := reset_wire
}
}}
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
clock_io := th.harnessClock
Nil
})
}
}
}

View File

@@ -6,12 +6,13 @@ import chisel3.util.{log2Up}
import freechips.rocketchip.config.{Field, Parameters, Config}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy.{LazyModule, ValName}
import freechips.rocketchip.devices.tilelink.BootROMParams
import freechips.rocketchip.devices.debug.{Debug}
import freechips.rocketchip.devices.tilelink.{BootROMLocated}
import freechips.rocketchip.devices.debug.{Debug, ExportDebug, DebugModuleKey, DMI}
import freechips.rocketchip.groundtest.{GroundTestSubsystem}
import freechips.rocketchip.tile._
import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams, ICacheParams}
import freechips.rocketchip.util.{AsyncResetReg}
import freechips.rocketchip.prci._
import testchipip._
import tracegen.{TraceGenSystem}
@@ -25,23 +26,15 @@ import sifive.blocks.devices.gpio._
import sifive.blocks.devices.uart._
import sifive.blocks.devices.spi._
import chipyard.{BuildTop, BuildSystem, TestSuitesKey, TestSuiteHelper}
import chipyard.{BuildTop, BuildSystem, ClockingSchemeGenerators, ClockingSchemeKey, TestSuitesKey, TestSuiteHelper}
/**
* TODO: Why do we need this?
*/
object ConfigValName {
implicit val valName = ValName("TestHarness")
}
import ConfigValName._
// -----------------------
// Common Config Fragments
// -----------------------
class WithBootROM extends Config((site, here, up) => {
case BootROMParams => BootROMParams(
contentFileName = s"./bootrom/bootrom.rv${site(XLen)}.img")
case BootROMLocated(x) => up(BootROMLocated(x), site).map(_.copy(contentFileName = s"./bootrom/bootrom.rv${site(XLen)}.img"))
})
// DOC include start: gpio config fragment
@@ -73,7 +66,7 @@ class WithL2TLBs(entries: Int) extends Config((site, here, up) => {
})
class WithTracegenSystem extends Config((site, here, up) => {
case BuildSystem => (p: Parameters) => LazyModule(new TraceGenSystem()(p))
case BuildSystem => (p: Parameters) => new TraceGenSystem()(p)
})
/**
@@ -105,7 +98,8 @@ class WithMultiRoCCHwacha(harts: Int*) extends Config(
case MultiRoCCKey => {
up(MultiRoCCKey, site) ++ harts.distinct.map{ i =>
(i -> Seq((p: Parameters) => {
LazyModule(new Hwacha()(p)).suggestName("hwacha")
val hwacha = LazyModule(new Hwacha()(p))
hwacha
}))
}
}
@@ -156,3 +150,23 @@ class WithHwachaTest extends Config((site, here, up) => {
"SRC_EXTENSION = $(base_dir)/hwacha/$(src_path)/*.scala" + "\nDISASM_EXTENSION = --extension=hwacha"
}
})
// The default RocketChip BaseSubsystem drives its diplomatic clock graph
// with the implicit clocks of Subsystem. Don't do that, instead we extend
// the diplomacy graph upwards into the ChipTop, where we connect it to
// our clock drivers
class WithNoSubsystemDrivenClocks extends Config((site, here, up) => {
case SubsystemDriveAsyncClockGroupsKey => None
})
class WithTileDividedClock extends Config((site, here, up) => {
case ClockingSchemeKey => ClockingSchemeGenerators.harnessDividedClock
})
class WithDMIDTM extends Config((site, here, up) => {
case ExportDebug => up(ExportDebug, site).copy(protocols = Set(DMI))
})
class WithNoDebug extends Config((site, here, up) => {
case DebugModuleKey => None
})

View File

@@ -2,11 +2,13 @@ package chipyard
package object iobinders {
import chisel3._
import chisel3.util.experimental.{BoringUtils}
import chisel3.experimental.{Analog, IO}
import freechips.rocketchip.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike}
import freechips.rocketchip.devices.debug._
import freechips.rocketchip.jtag.{JTAGIO}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.system.{SimAXIMem}
import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters}
@@ -41,7 +43,7 @@ import scala.reflect.{ClassTag}
// DOC include start: IOBinders
// This type describes a function callable on the TestHarness instance. Its return type is unused.
type TestHarnessFunction = (chipyard.TestHarness) => Seq[Any]
type TestHarnessFunction = (chipyard.HasHarnessSignalReferences) => 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
@@ -163,30 +165,62 @@ object AddIOCells {
}
/**
* Add IO cells to a debug module and name the IO ports.
* @param psd A PSDIO bundle
* @param resetctrlOpt An optional ResetCtrlIO 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)
* Add IO cells to a debug module and name the IO ports, for debug IO which must go off-chip
* For on-chip debug IO, drive them appropriately
* Mostly copied from rocket-chip/src/main/scala/devices/debug/Periphery.scala
* @param system A BaseSubsystem that might have a debug module
* @return Returns a tuple2 of (Generated debug io ports, Generated IOCells)
*/
def debug(psd: PSDIO, resetctrlOpt: Option[ResetCtrlIO], debugOpt: Option[DebugIO])(implicit p: Parameters):
(PSDIO, Option[ResetCtrlIO], Option[DebugIO], Seq[IOCell]) = {
val (psdPort, psdIOs) = IOCell.generateIOFromSignal(
psd, Some("iocell_psd"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync)
val debugTuple = debugOpt.map(d =>
IOCell.generateIOFromSignal(d, Some("iocell_debug"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync))
val debugPortOpt: Option[DebugIO] = debugTuple.map(_._1)
val debugIOs: Seq[IOCell] = debugTuple.map(_._2).toSeq.flatten
debugPortOpt.foreach(_.suggestName("debug"))
def debug(system: HasPeripheryDebugModuleImp)(implicit p: Parameters): (Seq[Bundle], Seq[IOCell]) = {
system.debug.map { debug =>
val tlbus = system.outer.asInstanceOf[BaseSubsystem].locateTLBusWrapper(p(ExportDebug).slaveWhere)
val debug_clock = Wire(Clock()).suggestName("debug_clock")
val debug_reset = Wire(Reset()).suggestName("debug_reset")
debug_clock := false.B.asClock // must provide default assignment to avoid firrtl unassigned error
debug_reset := false.B // must provide default assignment to avoid firrtl unassigned error
BoringUtils.bore(tlbus.module.clock, Seq(debug_clock))
BoringUtils.bore(tlbus.module.reset, Seq(debug_reset))
val resetctrlTuple = resetctrlOpt.map(d =>
IOCell.generateIOFromSignal(d, Some("iocell_resetctrl"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync))
val resetctrlPortOpt: Option[ResetCtrlIO] = resetctrlTuple.map(_._1)
val resetctrlIOs: Seq[IOCell] = resetctrlTuple.map(_._2).toSeq.flatten
resetctrlPortOpt.foreach(_.suggestName("resetctrl"))
// We never use the PSDIO, so tie it off on-chip
system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) }
system.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := debug_reset.asBool } }
system.debug.map { d =>
// Tie off extTrigger
d.extTrigger.foreach { t =>
t.in.req := false.B
t.out.ack := t.out.req
}
// Tie off disableDebug
d.disableDebug.foreach { d => d := false.B }
// Drive JTAG on-chip IOs
d.systemjtag.map { j =>
j.reset := debug_reset
j.mfr_id := system.p(JtagDTMKey).idcodeManufId.U(11.W)
j.part_number := system.p(JtagDTMKey).idcodePartNum.U(16.W)
j.version := system.p(JtagDTMKey).idcodeVersion.U(4.W)
}
}
Debug.connectDebugClockAndReset(Some(debug), debug_clock)(system.p)
psdPort.suggestName("psd")
(psdPort, resetctrlPortOpt, debugPortOpt, psdIOs ++ debugIOs ++ resetctrlIOs)
// Add IOCells for the DMI/JTAG/APB ports
val dmiTuple = debug.clockeddmi.map { d =>
IOCell.generateIOFromSignal(d, Some("iocell_dmi"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync)
}
dmiTuple.map(_._1).foreach(_.suggestName("dmi"))
val jtagTuple = debug.systemjtag.map { j =>
IOCell.generateIOFromSignal(j.jtag, Some("iocell_jtag"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync)
}
jtagTuple.map(_._1).foreach(_.suggestName("jtag"))
val apbTuple = debug.apb.map { a =>
IOCell.generateIOFromSignal(a, Some("iocell_apb"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync)
}
apbTuple.map(_._1).foreach(_.suggestName("apb"))
val allTuples = (dmiTuple ++ jtagTuple ++ apbTuple).toSeq
(allTuples.map(_._1).toSeq, allTuples.flatMap(_._2).toSeq)
}.getOrElse((Nil, Nil))
}
/**
@@ -201,14 +235,14 @@ object AddIOCells {
}
def axi4(io: Seq[AXI4Bundle], node: AXI4SlaveNode, name: String): Seq[(AXI4Bundle, AXI4EdgeParameters, Seq[IOCell])] = {
io.zip(node.in).zipWithIndex.map{ case ((mem_axi4, (_, edge)), i) => {
io.zip(node.edges.in).zipWithIndex.map{ case ((mem_axi4, edge), i) => {
val (port, ios) = IOCell.generateIOFromSignal(mem_axi4, Some(s"iocell_${name}_axi4_slave_${i}"))
port.suggestName(s"${name}_axi4_slave_${i}")
(port, edge, ios)
}}
}
def axi4(io: Seq[AXI4Bundle], node: AXI4MasterNode, name: String): Seq[(AXI4Bundle, AXI4EdgeParameters, Seq[IOCell])] = {
io.zip(node.out).zipWithIndex.map{ case ((mem_axi4, (_, edge)), i) => {
io.zip(node.edges.out).zipWithIndex.map{ case ((mem_axi4, edge), i) => {
//val (port, ios) = IOCell.generateIOFromSignal(mem_axi4, Some(s"iocell_${name}_axi4_master_${i}"))
val port = IO(Flipped(AXI4Bundle(edge.bundle)))
val ios = IOCell.generateFromSignal(mem_axi4, port, Some(s"iocell_${name}_axi4_master_${i}"))
@@ -228,7 +262,7 @@ object AddIOCells {
class WithGPIOTiedOff extends OverrideIOBinder({
(system: HasPeripheryGPIOModuleImp) => {
val (ports2d, ioCells2d) = AddIOCells.gpio(system.gpio)
val harnessFn = (th: chipyard.TestHarness) => { ports2d.flatten.foreach(_ <> AnalogConst(0)); Nil }
val harnessFn = (th: HasHarnessSignalReferences) => { ports2d.flatten.foreach(_ <> AnalogConst(0)); Nil }
Seq((ports2d.flatten, ioCells2d.flatten, Some(harnessFn)))
}
})
@@ -237,7 +271,7 @@ class WithGPIOTiedOff extends OverrideIOBinder({
class WithUARTAdapter extends OverrideIOBinder({
(system: HasPeripheryUARTModuleImp) => {
val (ports, ioCells2d) = AddIOCells.uart(system.uart)
val harnessFn = (th: chipyard.TestHarness) => { UARTAdapter.connect(ports)(system.p); Nil }
val harnessFn = (th: HasHarnessSignalReferences) => { UARTAdapter.connect(ports)(system.p); Nil }
Seq((ports, ioCells2d.flatten, Some(harnessFn)))
}
})
@@ -245,7 +279,7 @@ class WithUARTAdapter extends OverrideIOBinder({
class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideIOBinder({
(system: HasPeripherySPIFlashModuleImp) => {
val (ports, ioCells2d) = AddIOCells.spi(system.qspi, "qspi")
val harnessFn = (th: chipyard.TestHarness) => { SimSPIFlashModel.connect(ports, th.reset, rdOnly)(system.p); Nil }
val harnessFn = (th: HasHarnessSignalReferences) => { SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p); Nil }
Seq((ports, ioCells2d.flatten, Some(harnessFn)))
}
})
@@ -253,8 +287,9 @@ class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideIOBinder({
class WithSimBlockDevice extends OverrideIOBinder({
(system: CanHavePeripheryBlockDeviceModuleImp) => system.bdev.map { bdev =>
val (port, ios) = AddIOCells.blockDev(bdev)
val harnessFn = (th: chipyard.TestHarness) => {
SimBlockDevice.connect(th.clock, th.reset.asBool, Some(port))(system.p)
val harnessFn = (th: HasHarnessSignalReferences) => {
// TODO: Using harness clock/reset will be incorrect when systemClock =/= harnessClock
SimBlockDevice.connect(th.harnessClock, th.harnessReset.asBool, Some(port))(system.p)
Nil
}
Seq((Seq(port), ios, Some(harnessFn)))
@@ -264,7 +299,7 @@ class WithSimBlockDevice extends OverrideIOBinder({
class WithBlockDeviceModel extends OverrideIOBinder({
(system: CanHavePeripheryBlockDeviceModuleImp) => system.bdev.map { bdev =>
val (port, ios) = AddIOCells.blockDev(bdev)
val harnessFn = (th: chipyard.TestHarness) => {
val harnessFn = (th: HasHarnessSignalReferences) => {
BlockDeviceModel.connect(Some(port))(system.p)
Nil
}
@@ -287,7 +322,7 @@ class WithSimAXIMem extends OverrideIOBinder({
val peiTuples = AddIOCells.axi4(system.mem_axi4, system.memAXI4Node, "mem")
// TODO: we are inlining the connectMem method of SimAXIMem because
// it takes in a dut rather than seq of axi4 ports
val harnessFn = (th: chipyard.TestHarness) => {
val harnessFn = (th: HasHarnessSignalReferences) => {
peiTuples.map { case (port, edge, ios) =>
val mem = LazyModule(new SimAXIMem(edge, size = p(ExtMem).get.master.size))
Module(mem.module).suggestName("mem")
@@ -304,14 +339,15 @@ class WithBlackBoxSimMem extends OverrideIOBinder({
(system: CanHaveMasterAXI4MemPort) => {
implicit val p: Parameters = GetSystemParameters(system)
val peiTuples = AddIOCells.axi4(system.mem_axi4, system.memAXI4Node, "mem")
val harnessFn = (th: chipyard.TestHarness) => {
val harnessFn = (th: HasHarnessSignalReferences) => {
peiTuples.map { case (port, edge, ios) =>
val memSize = p(ExtMem).get.master.size
val lineSize = p(CacheBlockBytes)
val mem = Module(new SimDRAM(memSize, lineSize, edge.bundle))
mem.io.axi <> port
mem.io.clock := th.clock
mem.io.reset := th.reset
// TODO: Using harness clock/reset will be incorrect when systemClock =/= harnessClock
mem.io.clock := th.harnessClock
mem.io.reset := th.harnessReset
}
Nil
}
@@ -323,7 +359,7 @@ class WithSimAXIMMIO extends OverrideIOBinder({
(system: CanHaveMasterAXI4MMIOPort) => {
implicit val p: Parameters = GetSystemParameters(system)
val peiTuples = AddIOCells.axi4(system.mmio_axi4, system.mmioAXI4Node, "mmio_mem")
val harnessFn = (th: chipyard.TestHarness) => {
val harnessFn = (th: HasHarnessSignalReferences) => {
peiTuples.zipWithIndex.map { case ((port, edge, ios), i) =>
val mmio_mem = LazyModule(new SimAXIMem(edge, size = 4096))
Module(mmio_mem.module).suggestName(s"mmio_mem_${i}")
@@ -343,7 +379,7 @@ class WithTieOffInterrupts extends OverrideIOBinder({
(system: HasExtInterruptsModuleImp) => {
val (port, ioCells) = IOCell.generateIOFromSignal(system.interrupts, Some("iocell_interrupts"))
port.suggestName("interrupts")
val harnessFn = (th: chipyard.TestHarness) => { port := 0.U; Nil }
val harnessFn = (th: HasHarnessSignalReferences) => { port := 0.U; Nil }
Seq((Seq(port), ioCells, Some(harnessFn)))
}
})
@@ -351,7 +387,7 @@ class WithTieOffInterrupts extends OverrideIOBinder({
class WithTieOffL2FBusAXI extends OverrideIOBinder({
(system: CanHaveSlaveAXI4Port) => {
val peiTuples = AddIOCells.axi4(system.l2_frontend_bus_axi4, system.l2FrontendAXI4Node, "l2_fbus")
val harnessFn = (th: chipyard.TestHarness) => {
val harnessFn = (th: HasHarnessSignalReferences) => {
peiTuples.zipWithIndex.map { case ((port, edge, ios), i) =>
port := DontCare // tieoff doesn't completely tie-off, for some reason
port.tieoff()
@@ -362,43 +398,60 @@ class WithTieOffL2FBusAXI extends OverrideIOBinder({
}
})
class WithTiedOffDebug extends OverrideIOBinder({
class WithSimDebug extends OverrideIOBinder({
(system: HasPeripheryDebugModuleImp) => {
val (psdPort, resetctrlOpt, debugPortOpt, ioCells) =
AddIOCells.debug(system.psd, system.resetctrl, system.debug)(system.p)
val harnessFn = (th: chipyard.TestHarness) => {
Debug.tieoffDebug(debugPortOpt, resetctrlOpt, Some(psdPort))(system.p)
// tieoffDebug doesn't actually tie everything off :/
debugPortOpt.foreach { d =>
d.clockeddmi.foreach({ cdmi => cdmi.dmi.req.bits := DontCare; cdmi.dmiClock := th.clock })
d.dmactiveAck := DontCare
d.clock := th.clock
val (ports, iocells) = AddIOCells.debug(system)(system.p)
val harnessFn = (th: HasHarnessSignalReferences) => {
val dtm_success = WireInit(false.B)
when (dtm_success) { th.success := true.B }
ports.map {
case d: ClockedDMIIO =>
val dtm = Module(new SimDTM()(system.p)).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success)
case j: JTAGIO =>
val jtag = Module(new SimJTAG(tickDelay=3)).connect(j, th.harnessClock, th.harnessReset.asBool, ~(th.harnessReset.asBool), dtm_success)
case _ =>
require(false, "We only support DMI or JTAG simulated debug connections")
}
Nil
}
Seq((Seq(psdPort) ++ resetctrlOpt ++ debugPortOpt.toSeq, Nil, Some(harnessFn)))
Seq((ports, iocells, Some(harnessFn)))
}
})
class WithSimDebug extends OverrideIOBinder({
class WithTiedOffDebug extends OverrideIOBinder({
(system: HasPeripheryDebugModuleImp) => {
val (psdPort, resetctrlPortOpt, debugPortOpt, ioCells) =
AddIOCells.debug(system.psd, system.resetctrl, system.debug)(system.p)
val harnessFn = (th: chipyard.TestHarness) => {
val dtm_success = Wire(Bool())
Debug.connectDebug(debugPortOpt, resetctrlPortOpt, 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)
val (ports, iocells) = AddIOCells.debug(system)(system.p)
val harnessFn = (th: HasHarnessSignalReferences) => {
ports.map {
case d: ClockedDMIIO =>
d.dmi.req.valid := false.B
d.dmi.req.bits := DontCare
d.dmi.resp.ready := true.B
d.dmiClock := false.B.asClock
d.dmiReset := true.B
case j: JTAGIO =>
j.TCK := true.B.asClock
j.TMS := true.B
j.TDI := true.B
j.TRSTn.foreach { r => r := true.B }
case a: ClockedAPBBundle =>
a.tieoff()
a.clock := false.B.asClock
a.reset := true.B.asAsyncReset
a.psel := false.B
a.penable := false.B
case _ => require(false)
}
Nil
}
Seq((Seq(psdPort) ++ debugPortOpt.toSeq, ioCells, Some(harnessFn)))
Seq((ports, iocells, Some(harnessFn)))
}
})
class WithTiedOffSerial extends OverrideIOBinder({
(system: CanHavePeripherySerialModuleImp) => system.serial.map({ serial =>
val (port, ioCells) = AddIOCells.serial(serial)
val harnessFn = (th: chipyard.TestHarness) => {
val harnessFn = (th: HasHarnessSignalReferences) => {
SerialAdapter.tieoff(port)
Nil
}
@@ -409,8 +462,8 @@ class WithTiedOffSerial extends OverrideIOBinder({
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)
val harnessFn = (th: HasHarnessSignalReferences) => {
val ser_success = SerialAdapter.connectSimSerial(port, th.harnessClock, th.harnessReset)
when (ser_success) { th.success := true.B }
Nil
}
@@ -422,7 +475,7 @@ class WithTraceGenSuccessBinder extends OverrideIOBinder({
(system: TraceGenSystemModuleImp) => {
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 }
val harnessFn = (th: HasHarnessSignalReferences) => { when (successPort) { th.success := true.B }; Nil }
Seq((Seq(successPort), ioCells, Some(harnessFn)))
}
})

View File

@@ -8,6 +8,7 @@ package chipyard
import chisel3._
import chisel3.internal.sourceinfo.{SourceInfo}
import freechips.rocketchip.prci._
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp, ExportDebug}
@@ -26,12 +27,11 @@ import boom.common.{BoomTile}
import testchipip.{DromajoHelper, CanHavePeripherySerial, SerialKey}
trait CanHaveHTIF { this: BaseSubsystem =>
// Advertise HTIF if system can communicate with fesvr
if (this match {
case _: CanHavePeripherySerial if p(SerialKey) => true
case _: HasPeripheryDebug if p(ExportDebug).protocols.nonEmpty => true
case _: HasPeripheryDebug if p(ExportDebug).dmi => true
case _ => false
}) {
ResourceBinding {
@@ -47,7 +47,6 @@ trait CanHaveHTIF { this: BaseSubsystem =>
}
}
class ChipyardSubsystem(implicit p: Parameters) extends BaseSubsystem
with HasTiles
with CanHaveHTIF
@@ -56,25 +55,17 @@ class ChipyardSubsystem(implicit p: Parameters) extends BaseSubsystem
case r: RocketTile => r.module.core.rocketImpl.coreMonitorBundle
case b: BoomTile => b.module.core.coreMonitorBundle
}.toList
override lazy val module = new ChipyardSubsystemModuleImp(this)
}
class ChipyardSubsystemModuleImp[+L <: ChipyardSubsystem](_outer: L) extends BaseSubsystemModuleImp(_outer)
with HasResetVectorWire
with HasTilesModuleImp
{
for (i <- 0 until outer.tiles.size) {
val wire = tile_inputs(i)
wire.hartid := outer.hartIdList(i).U
wire.reset_vector := global_reset_vector
}
// create file with core params
ElaborationArtefacts.add("""core.config""", outer.tiles.map(x => x.module.toString).mkString("\n"))
// Generate C header with relevant information for Dromajo
// This is included in the `dromajo_params.h` header file
DromajoHelper.addArtefacts()
DromajoHelper.addArtefacts(InSubsystem)
}

View File

@@ -26,8 +26,10 @@ class ChipyardSystem(implicit p: Parameters) extends ChipyardSubsystem
with CanHaveMasterAXI4MemPort
with CanHaveMasterAXI4MMIOPort
with CanHaveSlaveAXI4Port
with HasPeripheryBootROM
{
val bootROM = p(BootROMLocated(location)).map { BootROM.attach(_, this, CBUS) }
val maskROMs = p(MaskROMLocated(location)).map { MaskROM.attach(_, this, CBUS) }
override lazy val module = new ChipyardSystemModule(this)
}
@@ -37,5 +39,4 @@ class ChipyardSystem(implicit p: Parameters) extends ChipyardSubsystem
class ChipyardSystemModule[+L <: ChipyardSystem](_outer: L) extends ChipyardSubsystemModuleImp(_outer)
with HasRTCModuleImp
with HasExtInterruptsModuleImp
with HasPeripheryBootROMModuleImp
with DontTouch

View File

@@ -5,33 +5,41 @@ import chisel3._
import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.config.{Field, Parameters}
import chipyard.iobinders.{TestHarnessFunction}
import chipyard.config.ConfigValName._
// -------------------------------
// BOOM and/or Rocket Test Harness
// Chipyard Test Harness
// -------------------------------
case object BuildTop extends Field[Parameters => HasTestHarnessFunctions]((p: Parameters) => Module(new ChipTop()(p)))
case object BuildTop extends Field[Parameters => LazyModule with HasTestHarnessFunctions]((p: Parameters) => new ChipTop()(p))
trait HasTestHarnessFunctions {
val harnessFunctions: Seq[TestHarnessFunction]
}
class TestHarness(implicit val p: Parameters) extends Module {
trait HasHarnessSignalReferences {
def harnessClock: Clock
def harnessReset: Reset
def dutReset: Reset
def success: Bool
}
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences {
val io = IO(new Bundle {
val success = Output(Bool())
})
val dut = p(BuildTop)(p)
val ldut = LazyModule(p(BuildTop)(p)).suggestName("chiptop")
val dut = Module(ldut.module)
io.success := false.B
val harnessClock = clock
val harnessReset = WireInit(reset)
val success = io.success
// dutReset assignment can be overridden via a harnessFunction, but by default it is just reset
val dutReset = WireDefault(if (p(GlobalResetSchemeKey).pinIsAsync) reset.asAsyncReset else reset)
dut.harnessFunctions.foreach(_(this))
def success = io.success
def harnessReset = this.reset.asBool
ldut.harnessFunctions.foreach(_(this))
}

View File

@@ -11,12 +11,14 @@ class AbstractConfig extends Config(
new chipyard.iobinders.WithUARTAdapter ++ // display UART with a SimUARTAdapter
new chipyard.iobinders.WithTieOffInterrupts ++ // tie off top-level interrupts
new chipyard.iobinders.WithBlackBoxSimMem ++ // drive the master AXI4 memory with a blackbox DRAMSim model
new chipyard.iobinders.WithTiedOffDebug ++ // tie off debug (since we are using SimSerial for testing)
new chipyard.iobinders.WithSimDebug ++ // attach SimJTAG
new chipyard.iobinders.WithSimSerial ++ // drive TSI with SimSerial for testing
new testchipip.WithTSI ++ // use testchipip serial offchip link
new chipyard.config.WithBootROM ++ // use default bootrom
new chipyard.config.WithUART ++ // add a UART
new chipyard.config.WithL2TLBs(1024) ++ // use L2 TLBs
new chipyard.config.WithNoSubsystemDrivenClocks ++ // drive the subsystem diplomatic clocks from ChipTop instead of using implicit clocks
new freechips.rocketchip.subsystem.WithJtagDTM ++ // set the debug module to expose a JTAG port
new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip)
new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip)
new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache

View File

@@ -14,6 +14,6 @@ class ArianeConfig extends Config(
class dmiArianeConfig extends Config(
new chipyard.iobinders.WithTiedOffSerial ++ // Tie off the serial port, override default instantiation of SimSerial
new chipyard.iobinders.WithSimDebug ++ // add SimDebug and use it to drive simulation, override default tie-off debug
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new ariane.WithNArianeCores(1) ++ // single Ariane core
new chipyard.config.AbstractConfig)

View File

@@ -23,18 +23,10 @@ class GemminiRocketConfig extends Config(
new chipyard.config.AbstractConfig)
// DOC include end: GemminiRocketConfig
// DOC include start: JtagRocket
class jtagRocketConfig extends Config(
new chipyard.iobinders.WithSimDebug ++ // add SimDebug, in addition to default SimSerial
new freechips.rocketchip.subsystem.WithJtagDTM ++ // sets DTM communication interface to JTAG
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)
// DOC include end: JtagRocket
// DOC include start: DmiRocket
class dmiRocketConfig extends Config(
new chipyard.iobinders.WithTiedOffSerial ++ // tie-off serial, override default add SimSerial
new chipyard.iobinders.WithSimDebug ++ // add SimDebug, override default tie-off debug
new chipyard.iobinders.WithTiedOffSerial ++ // don't use serial to drive the chip, since we use DMI instead
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)
// DOC include end: DmiRocket
@@ -184,3 +176,13 @@ class MMIORocketConfig extends Config(
new freechips.rocketchip.subsystem.WithDefaultSlavePort ++ // add default external slave port
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)
// NOTE: This config doesn't work yet because SimWidgets in the TestHarness
// always get the TestHarness clock. The Tiles and Uncore receive the correct clocks
class DividedClockRocketConfig extends Config(
new chipyard.config.WithTileDividedClock ++ // Put the Tile on its own clock domain
new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)

View File

@@ -7,6 +7,7 @@ class TraceGenConfig extends Config(
new chipyard.iobinders.WithBlackBoxSimMem ++
new chipyard.iobinders.WithTraceGenSuccessBinder ++
new chipyard.config.WithTracegenSystem ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
new tracegen.WithTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 0, nSets = 16, nWays = 2) }) ++
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++
new freechips.rocketchip.groundtest.GroundTestBaseConfig)
@@ -15,6 +16,7 @@ class NonBlockingTraceGenConfig extends Config(
new chipyard.iobinders.WithBlackBoxSimMem ++
new chipyard.iobinders.WithTraceGenSuccessBinder ++
new chipyard.config.WithTracegenSystem ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
new tracegen.WithTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 2, nSets = 16, nWays = 2) }) ++
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++
new freechips.rocketchip.groundtest.GroundTestBaseConfig)
@@ -23,6 +25,7 @@ class BoomTraceGenConfig extends Config(
new chipyard.iobinders.WithBlackBoxSimMem ++
new chipyard.iobinders.WithTraceGenSuccessBinder ++
new chipyard.config.WithTracegenSystem ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
new tracegen.WithBoomTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 8, nSets = 16, nWays = 2) }) ++
new freechips.rocketchip.subsystem.WithInclusiveCache ++
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++
@@ -32,6 +35,7 @@ class NonBlockingTraceGenL2Config extends Config(
new chipyard.iobinders.WithBlackBoxSimMem ++
new chipyard.iobinders.WithTraceGenSuccessBinder ++
new chipyard.config.WithTracegenSystem ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
new tracegen.WithL2TraceGen()(List.fill(2)(DCacheParams(nMSHRs = 2, nSets = 16, nWays = 4))) ++
new freechips.rocketchip.subsystem.WithInclusiveCache ++
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++
@@ -41,6 +45,7 @@ class NonBlockingTraceGenL2RingConfig extends Config(
new chipyard.iobinders.WithBlackBoxSimMem ++
new chipyard.iobinders.WithTraceGenSuccessBinder ++
new chipyard.config.WithTracegenSystem ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
new tracegen.WithL2TraceGen()(List.fill(2)(DCacheParams(nMSHRs = 2, nSets = 16, nWays = 4))) ++
new testchipip.WithRingSystemBus ++
new freechips.rocketchip.subsystem.WithInclusiveCache ++

View File

@@ -23,7 +23,7 @@ class TutorialStarterConfig extends Config(
new chipyard.iobinders.WithUARTAdapter ++ // Connect a SimUART adapter to display UART on stdout
new chipyard.iobinders.WithBlackBoxSimMem ++ // Connect simulated external memory
new chipyard.iobinders.WithTieOffInterrupts ++ // Do not simulate external interrupts
new chipyard.iobinders.WithTiedOffDebug ++ // Disconnect the debug module, since we use TSI for bring-up
new chipyard.iobinders.WithSimDebug ++ // Connect SimJTAG (or SimDTM) widgets to debug ios
new chipyard.iobinders.WithSimSerial ++ // Connect external SimSerial widget to drive TSI
// Config fragments below this line affect hardware generation
@@ -31,6 +31,7 @@ class TutorialStarterConfig extends Config(
new testchipip.WithTSI ++ // Add a TSI (Test Serial Interface) widget to bring-up the core
new chipyard.config.WithBootROM ++ // Use the Chipyard BootROM
new chipyard.config.WithUART ++ // Add a UART
new chipyard.config.WithNoSubsystemDrivenClocks ++ // Don't drive the subsystem clocks from within the subsystem
// CUSTOMIZE THE CORE
// Uncomment out one (or multiple) of the lines below, and choose
@@ -42,13 +43,19 @@ class TutorialStarterConfig extends Config(
// Uncomment this line, and specify a size if you want to have a L2
// new freechips.rocketchip.subsystem.WithInclusiveCache(nBanks=1, nWays=4, capacityKB=128) ++
// Set the debug module to expose an external JTAG port
new freechips.rocketchip.subsystem.WithJtagDTM ++
// For simpler designs, we want to minimize IOs on
// our Top. These config fragments remove unnecessary
// ports
new freechips.rocketchip.subsystem.WithNoMMIOPort ++
new freechips.rocketchip.subsystem.WithNoSlavePort ++
new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ // hierarchical buses including mbus+l2
// Use the standard hierarchical bus topology including mbus+l2
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++
// BaseConfig configures "bare" rocketchip system
new freechips.rocketchip.system.BaseConfig
)
@@ -59,12 +66,13 @@ class TutorialMMIOConfig extends Config(
new chipyard.iobinders.WithUARTAdapter ++
new chipyard.iobinders.WithBlackBoxSimMem ++
new chipyard.iobinders.WithTieOffInterrupts ++
new chipyard.iobinders.WithTiedOffDebug ++
new chipyard.iobinders.WithSimDebug ++
new chipyard.iobinders.WithSimSerial ++
new testchipip.WithTSI ++
new chipyard.config.WithBootROM ++
new chipyard.config.WithUART ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
// Attach either a TileLink or AXI4 version of GCD
// Uncomment one of the below lines
@@ -74,6 +82,7 @@ class TutorialMMIOConfig extends Config(
// For this demonstration we assume the base system is a single-core Rocket, for fast elaboration
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new freechips.rocketchip.subsystem.WithInclusiveCache ++
new freechips.rocketchip.subsystem.WithJtagDTM ++
new freechips.rocketchip.subsystem.WithNoMMIOPort ++
new freechips.rocketchip.subsystem.WithNoSlavePort ++
new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++
@@ -86,18 +95,20 @@ class TutorialSha3Config extends Config(
new chipyard.iobinders.WithUARTAdapter ++
new chipyard.iobinders.WithBlackBoxSimMem ++
new chipyard.iobinders.WithTieOffInterrupts ++
new chipyard.iobinders.WithTiedOffDebug ++
new chipyard.iobinders.WithSimDebug ++
new chipyard.iobinders.WithSimSerial ++
new testchipip.WithTSI ++
new chipyard.config.WithBootROM ++
new chipyard.config.WithUART ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
// Uncomment this line once you added SHA3 to the build.sbt, and cloned the SHA3 repo
// new sha3.WithSha3Accel ++
// For this demonstration we assume the base system is a single-core Rocket, for fast elaboration
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new freechips.rocketchip.subsystem.WithJtagDTM ++
new freechips.rocketchip.subsystem.WithInclusiveCache ++
new freechips.rocketchip.subsystem.WithNoMMIOPort ++
new freechips.rocketchip.subsystem.WithNoSlavePort ++
@@ -111,12 +122,13 @@ class TutorialSha3BlackBoxConfig extends Config(
new chipyard.iobinders.WithUARTAdapter ++
new chipyard.iobinders.WithBlackBoxSimMem ++
new chipyard.iobinders.WithTieOffInterrupts ++
new chipyard.iobinders.WithTiedOffDebug ++
new chipyard.iobinders.WithSimDebug ++
new chipyard.iobinders.WithSimSerial ++
new testchipip.WithTSI ++
new chipyard.config.WithBootROM ++
new chipyard.config.WithUART ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
// Uncomment these lines once SHA3 is integrated
// new sha3.WithSha3BlackBox ++ // Specify we want the Black-box verilog version of Sha3 Ctrl
@@ -124,6 +136,7 @@ class TutorialSha3BlackBoxConfig extends Config(
// For this demonstration we assume the base system is a single-core Rocket, for fast elaboration
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new freechips.rocketchip.subsystem.WithJtagDTM ++
new freechips.rocketchip.subsystem.WithInclusiveCache ++
new freechips.rocketchip.subsystem.WithNoMMIOPort ++
new freechips.rocketchip.subsystem.WithNoSlavePort ++

View File

@@ -58,7 +58,7 @@ class WithBlockDeviceBridge extends OverrideIOBinder({
class WithFASEDBridge extends OverrideIOBinder({
(system: CanHaveMasterAXI4MemPort) => {
implicit val p: Parameters = GetSystemParameters(system)
(system.mem_axi4 zip system.memAXI4Node.in).foreach({ case (axi4, (_, edge)) =>
(system.mem_axi4 zip system.memAXI4Node.edges.in).foreach({ case (axi4, edge) =>
val nastiKey = NastiParameters(axi4.r.bits.data.getWidth,
axi4.ar.bits.addr.getWidth,
axi4.ar.bits.id.getWidth)

View File

@@ -3,13 +3,17 @@
package firesim.firesim
import chisel3._
import chisel3.experimental.{IO}
import freechips.rocketchip.prci._
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey}
import freechips.rocketchip.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.diplomacy.{LazyModule, InModuleBody}
import freechips.rocketchip.util.{ResetCatchAndSync}
import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge}
import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock}
import chipyard.{BuildSystem}
import chipyard.{BuildSystem, BuildTop, HasHarnessSignalReferences, ChipyardSubsystem, ClockingSchemeKey, ChipTop}
import chipyard.iobinders.{IOBinders}
// Determines the number of times to instantiate the DUT in the harness.
@@ -20,6 +24,16 @@ class WithNumNodes(n: Int) extends Config((pname, site, here) => {
case NumNodes => n
})
// Note, the main prerequisite for supporting an additional clock domain in a
// FireSim simulation is to supply an additional clock parameter
// (RationalClock) to the clock bridge (RationalClockBridge). The bridge
// produces a vector of clocks, based on the provided parameter list, which you
// may use freely without further modifications to your target design.
case class FireSimClockParameters(additionalClocks: Seq[RationalClock]) {
def numClocks(): Int = additionalClocks.size + 1
}
case object FireSimClockKey extends Field[FireSimClockParameters](FireSimClockParameters(Seq()))
// Hacky: Set before each node is generated. Ideally we'd give IO binders
// accesses to the the Harness's parameters instance. We could then alter that.
object NodeIdx {
@@ -28,33 +42,125 @@ object NodeIdx {
def apply(): Int = idx
}
class FireSim(implicit val p: Parameters) extends RawModule {
freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary())
val clockBridge = Module(new RationalClockBridge)
val clock = clockBridge.io.clocks.head
val reset = WireInit(false.B)
withClockAndReset(clock, reset) {
// Instantiate multiple instances of the DUT to implement supernode
val targets = Seq.fill(p(NumNodes)) {
// It's not a RC bump without some hacks...
// Copy the AsyncClockGroupsKey to generate a fresh node on each
// instantiation of the dut, otherwise the initial instance will be
// reused across each node
import freechips.rocketchip.subsystem.AsyncClockGroupsKey
val lazyModule = p(BuildSystem)(p.alterPartial({
case AsyncClockGroupsKey => p(AsyncClockGroupsKey).copy
}))
(lazyModule, Module(lazyModule.module))
class WithFireSimSimpleClocks extends Config((site, here, up) => {
case ClockingSchemeKey => { chiptop: ChipTop =>
implicit val p = chiptop.p
val implicitClockSourceNode = ClockSourceNode(Seq(ClockSourceParameters()))
chiptop.implicitClockSinkNode := implicitClockSourceNode
// Drive the diplomaticclock graph of the DigitalTop (if present)
val simpleClockGroupSourceNode = chiptop.lSystem match {
case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => {
val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
l.asyncClockGroupsNode := n
Some(n)
}
case _ => None
}
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 LazyModule class instance
//
// Apply each partial function to each DUT instance
for ((lazyModule, module) <- targets) {
p(IOBinders).values.foreach(f => f(lazyModule) ++ f(module))
NodeIdx.increment()
InModuleBody {
val clock = IO(Input(Clock())).suggestName("clock")
val reset = IO(Input(Reset())).suggestName("reset")
implicitClockSourceNode.out.unzip._1.map { o =>
o.clock := clock
o.reset := reset
}
simpleClockGroupSourceNode.map { n => n.out.unzip._1.map { out: ClockGroupBundle =>
out.member.data.foreach { o =>
o.clock := clock
o.reset := reset
}
}}
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
clock := th.harnessClock
reset := th.harnessReset
Nil
})
}
}
})
class WithFireSimRationalTileDomain(multiplier: Int, divisor: Int) extends Config((site, here, up) => {
case FireSimClockKey => FireSimClockParameters(Seq(RationalClock("TileDomain", multiplier, divisor)))
case ClockingSchemeKey => { chiptop: ChipTop =>
implicit val p = chiptop.p
val implicitClockSourceNode = ClockSourceNode(Seq(ClockSourceParameters()))
chiptop.implicitClockSinkNode := implicitClockSourceNode
// Drive the diplomaticclock graph of the DigitalTop (if present)
val simpleClockGroupSourceNode = chiptop.lSystem match {
case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => {
val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
l.asyncClockGroupsNode := n
Some(n)
}
case _ => None
}
InModuleBody {
val uncore_clock = IO(Input(Clock())).suggestName("uncore_clock")
val tile_clock = IO(Input(Clock())).suggestName("tile_clock")
val reset = IO(Input(Reset())).suggestName("reset")
implicitClockSourceNode.out.unzip._1.map { o =>
o.clock := uncore_clock
o.reset := reset
}
simpleClockGroupSourceNode.map { n => n.out.unzip._1.map { out: ClockGroupBundle =>
out.member.elements.map { case (name, data) =>
// This is mega hacks, how are you actually supposed to do this?
if (name.contains("core")) {
data.clock := tile_clock
data.reset := ResetCatchAndSync(tile_clock, reset.asBool)
} else {
data.clock := uncore_clock
data.reset := reset
}
}
}}
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
uncore_clock := th.harnessClock
reset := th.harnessReset
th match {
case f: FireSim => tile_clock := f.additionalClocks(0)
case _ => throw new Exception("FireSimMultiClock must be used with FireSim")
}
Nil
})
}
}
})
class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSignalReferences {
freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary())
val clockBridge = Module(new RationalClockBridge(p(FireSimClockKey).additionalClocks:_*))
val harnessClock = clockBridge.io.clocks.head // This is the reference clock
val additionalClocks = clockBridge.io.clocks.tail
val harnessReset = WireInit(false.B)
val peekPokeBridge = PeekPokeBridge(harnessClock, harnessReset)
def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B }
def success = { require(false, "success should not be used in Firesim"); false.B }
// Instantiate multiple instances of the DUT to implement supernode
for (i <- 0 until p(NumNodes)) {
// It's not a RC bump without some hacks...
// Copy the AsyncClockGroupsKey to generate a fresh node on each
// instantiation of the dut, otherwise the initial instance will be
// reused across each node
import freechips.rocketchip.subsystem.AsyncClockGroupsKey
val lazyModule = LazyModule(p(BuildTop)(p.alterPartial({
case AsyncClockGroupsKey => p(AsyncClockGroupsKey).copy
})))
val module = Module(lazyModule.module)
require(lazyModule.harnessFunctions.size == 1, "There should only be 1 harness function to connect clock+reset")
lazyModule.harnessFunctions.foreach(_(this))
NodeIdx.increment()
}
}

View File

@@ -1,107 +0,0 @@
//See LICENSE for license details.
package firesim.firesim
import chisel3._
import freechips.rocketchip.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, RationalCrossing}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.util.{ResetCatchAndSync}
import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock}
import firesim.configs._
import boom.common.{WithRationalBoomTiles}
import chipyard.{BuildSystem, DigitalTop, DigitalTopModule}
import chipyard.config.ConfigValName._
import chipyard.iobinders.{IOBinders}
// WIP! This file is a sketch of one means of defining a multiclock target-design
// that can be simulated in FireSim, pending a canonicalized form in Chipyard.
//
// Note, the main prerequisite for supporting an additional clock domain in a
// FireSim simulation is to supply an additional clock parameter
// (RationalClock) to the clock bridge (RationalClockBridge). The bridge
// produces a vector of clocks, based on the provided parameter list, which you
// may use freely without further modifications to your target design.
case class FireSimClockParameters(additionalClocks: Seq[RationalClock]) {
def numClocks(): Int = additionalClocks.size + 1
}
case object FireSimClockKey extends Field[FireSimClockParameters](FireSimClockParameters(Seq()))
trait HasAdditionalClocks extends LazyModuleImp {
val clocks = IO(Vec(p(FireSimClockKey).numClocks, Input(Clock())))
}
// Presupposes only 1 or 2 clocks.
trait HasFireSimClockingImp extends HasAdditionalClocks {
val outer: HasTiles
val (tileClock, tileReset) = p(FireSimClockKey).additionalClocks.headOption match {
case Some(RationalClock(_, numer, denom)) if numer != denom => (clocks(1), ResetCatchAndSync(clocks(1), reset.toBool))
case None => (clocks.head, reset)
}
outer.tiles.foreach({ case tile =>
tile.module.clock := tileClock
tile.module.reset := tileReset
})
}
// Config Fragment
class WithSingleRationalTileDomain(multiplier: Int, divisor: Int) extends Config(
new WithRationalRocketTiles ++
new WithRationalBoomTiles ++
new Config((site, here, up) => {
case FireSimClockKey => FireSimClockParameters(Seq(RationalClock("TileDomain", multiplier, divisor)))
})
)
class HalfRateUncore extends WithSingleRationalTileDomain(2,1)
class WithFiresimMulticlockTop extends Config((site, here, up) => {
case BuildSystem => (p: Parameters) => LazyModule(new FiresimMulticlockTop()(p)).suggestName("system")
})
// Complete Config
class FireSimQuadRocketMulticlockConfig extends Config(
new HalfRateUncore ++
new WithFiresimMulticlockTop ++
new FireSimQuadRocketConfig)
// Top Definition
class FiresimMulticlockTop(implicit p: Parameters) extends chipyard.DigitalTop
{
override lazy val module = new FiresimMulticlockTopModule(this)
}
class FiresimMulticlockTopModule[+L <: DigitalTop](l: L) extends chipyard.DigitalTopModule(l) with HasFireSimClockingImp
// Harness Definition
class FireSimMulticlockPOC(implicit val p: Parameters) extends RawModule {
freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary())
val clockBridge = Module(new RationalClockBridge(p(FireSimClockKey).additionalClocks:_*))
val refClock = clockBridge.io.clocks.head
val reset = WireInit(false.B)
withClockAndReset(refClock, reset) {
// Instantiate multiple instances of the DUT to implement supernode
val targets = Seq.fill(p(NumNodes)) {
val lazyModule = p(BuildSystem)(p)
(lazyModule, Module(lazyModule.module))
}
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 ((lazyModule, module) <- targets) {
p(IOBinders).values.foreach(f => f(lazyModule) ++ f(module))
}
targets.collect({ case (_, t: HasAdditionalClocks) => t.clocks := clockBridge.io.clocks })
}
}

View File

@@ -10,7 +10,7 @@ import freechips.rocketchip.tile._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.rocket.DCacheParams
import freechips.rocketchip.subsystem._
import freechips.rocketchip.devices.tilelink.BootROMParams
import freechips.rocketchip.devices.tilelink.{BootROMLocated, BootROMParams}
import freechips.rocketchip.devices.debug.{DebugModuleParams, DebugModuleKey}
import freechips.rocketchip.diplomacy.LazyModule
import testchipip.{BlockDeviceKey, BlockDeviceConfig, SerialKey, TracePortKey, TracePortParams}
@@ -22,19 +22,18 @@ import testchipip.WithRingSystemBus
import firesim.bridges._
import firesim.configs._
import chipyard.config.ConfigValName._
class WithBootROM extends Config((site, here, up) => {
case BootROMParams => {
case BootROMLocated(x) => {
val chipyardBootROM = new File(s"./generators/testchipip/bootrom/bootrom.rv${site(XLen)}.img")
val firesimBootROM = new File(s"./target-rtl/chipyard/generators/testchipip/bootrom/bootrom.rv${site(XLen)}.img")
val bootROMPath = if (chipyardBootROM.exists()) {
val bootROMPath = if (chipyardBootROM.exists()) {
chipyardBootROM.getAbsolutePath()
} else {
firesimBootROM.getAbsolutePath()
}
BootROMParams(contentFileName = bootROMPath)
up(BootROMLocated(x), site).map(_.copy(contentFileName = bootROMPath))
}
})
@@ -67,6 +66,8 @@ class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small")
// Tweaks that are generally applied to all firesim configs
class WithFireSimConfigTweaks extends Config(
// Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset
new WithFireSimSimpleClocks ++
// Required*: When using FireSim-as-top to provide a correct path to the target bootrom source
new WithBootROM ++
// Optional*: Removing this will require adjusting the UART baud rate and
@@ -87,7 +88,9 @@ class WithFireSimConfigTweaks extends Config(
// Optional: Removing this will require using an initramfs under linux
new testchipip.WithBlockDevice ++
// Required*: Scale default baud rate with periphery bus frequency
new chipyard.config.WithUART(BigInt(3686400L))
new chipyard.config.WithUART(BigInt(3686400L)) ++
// Required: Do not support debug module w. JTAG until FIRRTL stops emitting @(posedge ~clock)
new chipyard.config.WithNoDebug
)
/*******************************************************************************
@@ -186,3 +189,14 @@ class FireSimArianeConfig extends Config(
new WithDefaultMemModel ++
new WithFireSimConfigTweaks ++
new chipyard.ArianeConfig)
//**********************************************************************************
//* Multiclock Configurations
//*********************************************************************************/
class FireSimMulticlockRocketConfig extends Config(
new WithFireSimRationalTileDomain(2, 1) ++
new WithDefaultFireSimBridges ++
new WithDefaultMemModel ++
new WithFireSimConfigTweaks ++
new chipyard.DividedClockRocketConfig)

View File

@@ -106,8 +106,8 @@ class BoomF1Tests extends FireSimTestSuite("FireSim", "DDR3FRFCFSLLC4MB_FireSimL
class RocketNICF1Tests extends FireSimTestSuite("FireSim", "WithNIC_DDR3FRFCFSLLC4MB_FireSimRocketConfig", "BaseF1Config")
// Multiclock tests
class RocketMulticlockF1Tests extends FireSimTestSuite(
"FireSimMulticlockPOC",
"FireSimQuadRocketMulticlockConfig",
"FireSim",
"FireSimMulticlockRocketConfig",
"WithSynthAsserts_BaseF1Config")
class ArianeF1Tests extends FireSimTestSuite("FireSim", "WithNIC_DDR3FRFCFSLLC4MB_FireSimArianeConfig", "BaseF1Config")

View File

@@ -12,6 +12,10 @@ class TraceGenSystem(implicit p: Parameters) extends BaseSubsystem
with CanHaveMasterAXI4MemPort {
def coreMonitorBundles = Nil
val tileStatusNodes = tiles.collect {
case t: GroundTestTile => t.statusNode.makeSink()
case t: BoomTraceGenTile => t.statusNode.makeSink()
}
override lazy val module = new TraceGenSystemModuleImp(this)
}
@@ -20,12 +24,8 @@ class TraceGenSystemModuleImp(outer: TraceGenSystem)
{
val success = IO(Output(Bool()))
outer.tiles.zipWithIndex.map { case(t, i) => t.module.constants.hartid := i.U }
val status = dontTouch(DebugCombiner(outer.tileStatusNodes.map(_.bundle)))
val status = dontTouch(DebugCombiner(outer.tiles.collect {
case t: GroundTestTile => t.module.status
case t: BoomTraceGenTile => t.module.status
}))
success := outer.tileCeaseSinkNode.in.head._1.asUInt.andR
}

View File

@@ -3,7 +3,7 @@ package tracegen
import chisel3._
import chisel3.util._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy.{SimpleDevice, LazyModule, SynchronousCrossing, ClockCrossingType}
import freechips.rocketchip.diplomacy.{SimpleDevice, LazyModule, SynchronousCrossing, ClockCrossingType, BundleBridgeSource}
import freechips.rocketchip.groundtest._
import freechips.rocketchip.rocket._
import freechips.rocketchip.rocket.constants.{MemoryOpConstants}
@@ -206,11 +206,13 @@ class BoomTraceGenTile private(
val cpuDevice: SimpleDevice = new SimpleDevice("groundtest", Nil)
val intOutwardNode: IntOutwardNode = IntIdentityNode()
val slaveNode: TLInwardNode = TLIdentityNode()
val statusNode = BundleBridgeSource(() => new GroundTestStatus)
val boom_params = p.alterMap(Map(TileKey -> BoomTileParams(
dcache=params.dcache,
core=BoomCoreParams(nPMPs=0, numLdqEntries=32, numStqEntries=32, useVM=false))))
val dcache = LazyModule(new BoomNonBlockingDCache(hartId)(boom_params))
core=BoomCoreParams(nPMPs=0, numLdqEntries=16, numStqEntries=16, useVM=false))))
val dcache = LazyModule(new BoomNonBlockingDCache(staticIdForMetadataUseOnly)(boom_params))
val masterNode: TLOutwardNode = TLIdentityNode() := visibilityNode := dcache.node
@@ -220,11 +222,11 @@ class BoomTraceGenTile private(
class BoomTraceGenTileModuleImp(outer: BoomTraceGenTile)
extends BaseTileModuleImp(outer){
val status = IO(new GroundTestStatus)
val status = outer.statusNode.bundle
val halt_and_catch_fire = None
val tracegen = Module(new TraceGenerator(outer.params.traceParams))
tracegen.io.hartid := constants.hartid
tracegen.io.hartid := outer.hartIdSinkNode.bundle
val ptw = Module(new DummyPTW(1))
val lsu = Module(new LSU()(outer.boom_params, outer.dcache.module.edge))

View File

@@ -1,11 +1,15 @@
// See LICENSE.SiFive for license details.
// See LICENSE.Berkeley for license details.
#include "verilated.h"
#if VM_TRACE
#include <memory>
#if CY_FST_TRACE
#include "verilated_fst_c.h"
#else
#include "verilated.h"
#include "verilated_vcd_c.h"
#endif
#endif // CY_FST_TRACE
#endif // VM_TRACE
#include <fesvr/dtm.h>
#include <fesvr/tsi.h>
#include "remote_bitbang.h"
@@ -110,9 +114,10 @@ int main(int argc, char** argv)
uint64_t max_cycles = -1;
int ret = 0;
bool print_cycles = false;
// Port numbers are 16 bit unsigned integers.
// Port numbers are 16 bit unsigned integers.
uint16_t rbb_port = 0;
#if VM_TRACE
const char* vcdfile_name = NULL;
FILE * vcdfile = NULL;
uint64_t start = 0;
#endif
@@ -157,6 +162,7 @@ int main(int argc, char** argv)
case 'o': opterr = 1; break;
#if VM_TRACE
case 'v': {
vcdfile_name = optarg;
vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w");
if (!vcdfile) {
std::cerr << "Unable to open " << optarg << " for VCD write\n";
@@ -264,17 +270,20 @@ done_processing:
#if VM_TRACE
Verilated::traceEverOn(true); // Verilator must compute traced signals
#if CY_FST_TRACE
std::unique_ptr<VerilatedFstC> tfp(new VerilatedFstC);
#else
std::unique_ptr<VerilatedVcdFILE> vcdfd(new VerilatedVcdFILE(vcdfile));
std::unique_ptr<VerilatedVcdC> tfp(new VerilatedVcdC(vcdfd.get()));
if (vcdfile) {
#endif // CY_FST_TRACE
if (vcdfile_name) {
tile->trace(tfp.get(), 99); // Trace 99 levels of hierarchy
tfp->open("");
tfp->open(vcdfile_name);
}
#endif
#endif // VM_TRACE
// RocketChip currently only supports RBB port 0, so this needs to stay here
jtag = new remote_bitbang_t(rbb_port);
dtm = new dtm_t(argc, argv);
tsi = new tsi_t(argc, argv);
signal(SIGTERM, handle_sigterm);
@@ -304,8 +313,7 @@ done_processing:
tile->reset = 0;
done_reset = true;
while (!dtm->done() && !jtag->done() && !tsi->done() &&
!tile->io_success && trace_count < max_cycles) {
do {
tile->clock = 0;
tile->eval();
#if VM_TRACE
@@ -322,6 +330,13 @@ done_processing:
#endif
trace_count++;
}
// for verilator multithreading. need to do 1 loop before checking if
// tsi exists, since tsi is created by verilated thread on the first
// serial_tick.
while ((!dtm || !dtm->done()) &&
(!jtag || !jtag->done()) &&
(!tsi || !tsi->done()) &&
!tile->io_success && trace_count < max_cycles);
#if VM_TRACE
if (tfp)
@@ -330,17 +345,17 @@ done_processing:
fclose(vcdfile);
#endif
if (dtm->exit_code())
if (dtm && dtm->exit_code())
{
fprintf(stderr, "*** FAILED *** via dtm (code = %d, seed %d) after %ld cycles\n", dtm->exit_code(), random_seed, trace_count);
ret = dtm->exit_code();
}
else if (tsi->exit_code())
else if (tsi && tsi->exit_code())
{
fprintf(stderr, "*** FAILED *** (code = %d, seed %d) after %ld cycles\n", tsi->exit_code(), random_seed, trace_count);
ret = tsi->exit_code();
}
else if (jtag->exit_code())
else if (jtag && jtag->exit_code())
{
fprintf(stderr, "*** FAILED *** via jtag (code = %d, seed %d) after %ld cycles\n", jtag->exit_code(), random_seed, trace_count);
ret = jtag->exit_code();

View File

@@ -6,8 +6,8 @@
set -e
set -o pipefail
RDIR=$(pwd)
CHIPYARD_DIR="${CHIPYARD_DIR:-$(git rev-parse --show-toplevel)}"
DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
CHIPYARD_DIR="$(dirname "$DIR")"
usage() {
echo "usage: ${0} [OPTIONS] [riscv-tools | esp-tools | ec2fast]"
@@ -134,18 +134,16 @@ SRCDIR="$(pwd)/toolchains" module_all qemu --prefix="${RISCV}" --target-list=ris
git submodule update --init $CHIPYARD_DIR/tools/dromajo/dromajo-src
make -C $CHIPYARD_DIR/tools/dromajo/dromajo-src/src
cd "$RDIR"
# create specific env.sh
{
echo "# auto-generated by build-toolchains.sh"
echo "export CHIPYARD_TOOLCHAIN_SOURCED=1"
echo "export RISCV=$(printf '%q' "$RISCV")"
echo "export PATH=\${RISCV}/bin:\${PATH}"
echo "export LD_LIBRARY_PATH=\${RISCV}/lib\${LD_LIBRARY_PATH:+":\${LD_LIBRARY_PATH}"}"
} > env-$TOOLCHAIN.sh
cat > "$CHIPYARD_DIR/env-$TOOLCHAIN.sh" <<EOF
# auto-generated by build-toolchains.sh
export CHIPYARD_TOOLCHAIN_SOURCED=1
export RISCV=$(printf '%q' "$RISCV")
export PATH=\${RISCV}/bin:\${PATH}
export LD_LIBRARY_PATH=\${RISCV}/lib\${LD_LIBRARY_PATH:+":\${LD_LIBRARY_PATH}"}
EOF
# create general env.sh
echo "# line auto-generated by build-toolchains.sh" >> env.sh
echo "source \$( realpath \$(dirname "\${BASH_SOURCE[0]:-\${\(%\):-%x}}") )/env-$TOOLCHAIN.sh" >> env.sh
echo "source $(printf '%q' "$CHIPYARD_DIR/env-$TOOLCHAIN.sh")" >> env.sh
echo "Toolchain Build Complete!"

View File

@@ -15,7 +15,7 @@ case ${ncpu} in
esac
# Allow user to override MAKE
[ -n "${MAKE}" ] || MAKE=$(command -v gnumake || command -v gmake || command -v make)
[ -n "${MAKE:+x}" ] || MAKE=$(command -v gnumake || command -v gmake || command -v make)
readonly MAKE

View File

@@ -17,10 +17,11 @@ if [ "$MINGIT" != "$(echo -e "$MINGIT\n$MYGIT" | sort -V | head -n1)" ]; then
false
fi
RDIR=$(git rev-parse --show-toplevel)
DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
CHIPYARD_DIR="$(dirname "$DIR")"
# Ignore toolchain submodules
cd "$RDIR"
cd "$CHIPYARD_DIR"
for name in toolchains/*-tools/*/ ; do
git config submodule."${name%/}".update none
done
@@ -71,8 +72,11 @@ git config submodule.sims/firesim.update none
git submodule update --init software/firemarshal
# Configure firemarshal to know where our firesim installation is
if [ ! -f $RDIR/software/firemarshal/marshal-config.yaml ]; then
echo "firesim-dir: '../../sims/firesim/'" > $RDIR/software/firemarshal/marshal-config.yaml
if [ ! -f ./software/firemarshal/marshal-config.yaml ]; then
echo "firesim-dir: '../../sims/firesim/'" > ./software/firemarshal/marshal-config.yaml
fi
echo "# line auto-generated by init-submodules-no-riscv-tools.sh" >> $RDIR/env.sh
echo "PATH=\$( realpath \$(dirname "\${BASH_SOURCE[0]:-\${\(%\):-%x}}") )/software/firemarshal:\$PATH" >> $RDIR/env.sh
echo "# line auto-generated by init-submodules-no-riscv-tools.sh" >> env.sh
echo '__DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"' >> env.sh
echo "PATH=\$__DIR/bin:\$PATH" >> env.sh
echo "PATH=\$__DIR/software/firemarshal:\$PATH" >> env.sh

76
scripts/numa_prefix Executable file
View File

@@ -0,0 +1,76 @@
#!/usr/bin/env python
#============================================================================
# - really simple script, which just prints out the numactl cmd to
# prefix before your actual command. it determines this based on free
# memory size attached to every node.
# - when you run this on a machine without `numactl`, the output is empty,
# so `$(numa_prefix) <cmd> <args>` turns in to `<cmd> <args>`.
# - when the machine has `numactl` installed, regardless of the socket-count
# on the machine, the resulting command is:
# `numactl -m <socket> -C <core-id list> -- <cmd> <args>`
# - example output from `numactl -H` on a 2 socket machine:
# available: 2 nodes (0-1)
# node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22
# node 0 size: 131026 MB
# node 0 free: 7934 MB
# node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23
# node 1 size: 65536 MB
# node 1 free: 429 MB
# node distances:
# node 0 1
# 0: 10 20
# 1: 20 10
#============================================================================
import subprocess
import re
import sys
which_proc = subprocess.Popen(["which", "numactl"], stdout=subprocess.PIPE)
out, err = which_proc.communicate()
if out != "":
numactl_proc = subprocess.Popen(["numactl", "-H"], stdout=subprocess.PIPE)
out, err = numactl_proc.communicate()
lines = out.split("\n")
line_idx = 0
head_line = lines[line_idx]
line_idx += 1
node_match = re.match(r"^ *available: +(\d+) nodes", head_line)
if node_match:
avail_nodes = node_match.group(1)
best_node_id = ""
best_cpus = ""
best_free_size = 0
# loop through available nodes, selecting the node with the most free mem
for i in avail_nodes:
cpu_line = lines[line_idx]
# mem. size unused. skip and use mem. free
mem_free_line = lines[line_idx + 2]
line_idx += 3
cpu_match = re.match(r"^ *node (\d+) cpus: (\d.*\d)$", cpu_line)
if cpu_match:
node_id = cpu_match.group(1)
cpus = cpu_match.group(2).replace(" ", ",")
mem_free_match = re.match(r"^ *node " + node_id + " free: (\d+) \S+$", mem_free_line)
if mem_free_match:
free_size = mem_free_match.group(1)
if int(free_size) > int(best_free_size):
best_node_id = node_id
best_cpus = cpus
best_free_size = free_size
else:
sys.exit("[ERROR] Malformed mem free line: " + mem_free_line)
else:
sys.exit("[ERROR] Malformed cpus line: " + cpu_line)
sys.stdout.write("numactl -m " + best_node_id + " -C " + best_cpus + " --")
else:
sys.exit("[ERROR] Malformed head line: " + head_line)

View File

@@ -24,4 +24,4 @@ sudo apt-get install -y device-tree-compiler
git clone http://git.veripool.org/git/verilator
cd verilator
git checkout v4.034
autoconf && ./configure && make -j16 && sudo make install
autoconf && ./configure && make -j$(nproc) && sudo make install

23
sims/common-sim-flags.mk Normal file
View File

@@ -0,0 +1,23 @@
#----------------------------------------------------------------------------------------
# common gcc configuration/optimization
#----------------------------------------------------------------------------------------
SIM_OPT_CXXFLAGS := -O3
SIM_CXXFLAGS = \
$(CXXFLAGS) \
$(SIM_OPT_CXXFLAGS) \
-std=c++11 \
-I$(RISCV)/include \
-I$(dramsim_dir) \
-I$(build_dir) \
$(EXTRA_SIM_CXXFLAGS)
SIM_LDFLAGS = \
$(LDFLAGS) \
-L$(RISCV)/lib \
-Wl,-rpath,$(RISCV)/lib \
-L$(sim_dir) \
-L$(dramsim_dir) \
-lfesvr \
-ldramsim \
$(EXTRA_SIM_LDFLAGS)

View File

@@ -41,16 +41,24 @@ include $(base_dir)/common.mk
#########################################################################################
VCS = vcs -full64
VCS_OPTS = -notice -line $(VCS_CC_OPTS) $(VCS_NONCC_OPTS) $(VCS_DEFINE_OPTS) $(EXTRA_SIM_SOURCES)
VCS_OPTS = $(VCS_CC_OPTS) $(VCS_NONCC_OPTS) $(PREPROC_DEFINES)
#########################################################################################
# vcs build paths
#########################################################################################
model_dir = $(build_dir)/$(long_name)
model_dir_debug = $(build_dir)/$(long_name).debug
#########################################################################################
# vcs simulator rules
#########################################################################################
$(sim): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS)
rm -rf csrc && $(VCS) $(VCS_OPTS) -o $@
rm -rf $(model_dir)
$(VCS) $(VCS_OPTS) $(EXTRA_SIM_SOURCES) -o $@ -Mdir=$(model_dir)
$(sim_debug): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS)
rm -rf csrc && $(VCS) $(VCS_OPTS) -o $@ \
rm -rf $(model_dir_debug)
$(VCS) $(VCS_OPTS) $(EXTRA_SIM_SOURCES) -o $@ -Mdir=$(model_dir_debug) \
+define+DEBUG
#########################################################################################
@@ -61,8 +69,14 @@ $(output_dir)/%.vpd: $(output_dir)/% $(sim_debug)
(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
# general cleanup rules
#########################################################################################
.PHONY: clean
.PHONY: clean clean-sim clean-sim-debug
clean:
rm -rf $(gen_dir) csrc $(sim_prefix)-* ucli.key vc_hdrs.h
rm -rf $(gen_dir) $(sim_prefix)-* ucli.key
clean-sim:
rm -rf $(model_dir) $(build_dir)/vc_hdrs.h $(sim) $(sim).daidir ucli.key
clean-sim-debug:
rm -rf $(model_dir_debug) $(build_dir)/vc_hdrs.h $(sim_debug) $(sim_debug).daidir ucli.key

View File

@@ -22,7 +22,7 @@ include $(base_dir)/variables.mk
sim_name = verilator
#########################################################################################
# vcs simulator types and rules
# verilator simulator types and rules
#########################################################################################
sim_prefix = simulator
sim = $(sim_dir)/$(sim_prefix)-$(MODEL_PACKAGE)-$(CONFIG)
@@ -47,35 +47,53 @@ debug: $(sim_debug)
include $(base_dir)/common.mk
#########################################################################################
# verilator binary and flags
# verilator-specific user-interface variables and commands
#########################################################################################
HELP_COMPILATION_VARIABLES += \
" VERILATOR_PROFILE = 'none' if no verilator profiling (default)" \
" 'all' if full verilator runtime profiling" \
" 'threads' if runtime thread profiling only" \
" VERILATOR_THREADS = how many threads the simulator will use (default 1)" \
" VERILATOR_FST_MODE = enable FST waveform instead of VCD. use with debug build"
#########################################################################################
# verilator/cxx binary and flags
#########################################################################################
VERILATOR := verilator --cc --exe
CXXFLAGS := \
$(CXXFLAGS) -O1 -std=c++11 \
-I$(RISCV)/include \
-I$(dramsim_dir) \
-D__STDC_FORMAT_MACROS \
$(EXTRA_SIM_CC_FLAGS)
#----------------------------------------------------------------------------------------
# user configs
#----------------------------------------------------------------------------------------
VERILATOR_PROFILE ?= none
RUNTIME_PROFILING_CFLAGS := $(if $(filter $(VERILATOR_PROFILE),all),-g -pg,)
RUNTIME_PROFILING_VFLAGS := $(if $(filter $(VERILATOR_PROFILE),all),\
--prof-threads --prof-cfuncs,\
$(if $(filter $(VERILATOR_PROFILE),threads),\
--prof-threads,))
LDFLAGS := \
$(LDFLAGS) \
-L$(sim_dir) \
-lpthread
VERILATOR_THREADS ?= 1
RUNTIME_THREADS := --threads $(VERILATOR_THREADS) --threads-dpi all
VERILATOR_CC_OPTS = \
VERILATOR_FST_MODE ?= 0
TRACING_OPTS := $(if $(filter $(VERILATOR_FST_MODE),0),\
--trace,--trace-fst --trace-threads 1)
TRACING_CFLAGS := $(if $(filter $(VERILATOR_FST_MODE),0),,-DCY_FST_TRACE)
#----------------------------------------------------------------------------------------
# verilation configuration/optimization
#----------------------------------------------------------------------------------------
# we initially had --noassert for performance, but several modules use
# assertions, including dramsim, so we enable --assert by default
VERILATOR_OPT_FLAGS := \
-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)" \
$(RISCV)/lib/libfesvr.a \
$(dramsim_lib)
--x-assign fast \
--x-initial fast \
--output-split 10000 \
--output-split-cfuncs 100
# default flags added for ariane
ARIANE_VERILATOR_FLAGS = \
# default flags added for external IP (ariane/NVDLA)
VERILOG_IP_VERILATOR_FLAGS := \
--unroll-count 256 \
-Werror-PINMISSING \
-Werror-IMPLICIT \
-Wno-PINCONNECTEMPTY \
-Wno-ASSIGNDLY \
-Wno-DECLFILENAME \
@@ -85,29 +103,66 @@ ARIANE_VERILATOR_FLAGS = \
-Wno-style \
-Wall
# normal flags used for chipyard builds (that are incompatible with ariane)
CHIPYARD_VERILATOR_FLAGS = \
# normal flags used for chipyard builds (that are incompatible with vlog ip aka ariane/NVDLA)
CHIPYARD_VERILATOR_FLAGS := \
--assert
# options dependent on whether external IP (ariane/NVDLA) or just chipyard is used
# NOTE: defer the evaluation of this until it is used!
PLATFORM_OPTS = $(shell \
if grep -qiP "module\s+(Ariane|NVDLA)" $(build_dir)/*.*v; \
then echo "$(VERILOG_IP_VERILATOR_FLAGS)"; \
else echo "$(CHIPYARD_VERILATOR_FLAGS)"; fi)
# Use --timescale to approximate timescale behavior of pre-4.034
TIMESCALE_OPTS := $(shell verilator --version | perl -lne 'if (/(\d.\d+)/ && $$1 >= 4.034) { print "--timescale 1ns/1ps"; }')
VERILATOR_NONCC_OPTS = \
$(TIMESCALE_OPTS) \
--top-module $(VLOG_MODEL) \
--vpi \
-Wno-fatal \
$(shell if ! grep -iq "module.*ariane" $(build_dir)/*.*v; then echo "$(CHIPYARD_VERILATOR_FLAGS)"; else echo "$(ARIANE_VERILATOR_FLAGS)"; fi) \
--output-split 10000 \
--output-split-cfuncs 100 \
--max-num-width 1048576 \
-f $(sim_common_files) \
$(sim_vsrcs)
VERILATOR_DEFINES = \
# see: https://github.com/ucb-bar/riscv-mini/issues/31
MAX_WIDTH_OPTS = $(shell verilator --version | perl -lne 'if (/(\d.\d+)/ && $$1 > 4.016) { print "--max-num-width 1048576"; }')
PREPROC_DEFINES := \
+define+PRINTF_COND=\$$c\(\"verbose\",\"\&\&\"\,\"done_reset\"\) \
+define+STOP_COND=\$$c\(\"done_reset\"\)
VERILATOR_OPTS = $(VERILATOR_CC_OPTS) $(VERILATOR_NONCC_OPTS) $(VERILATOR_DEFINES) $(EXTRA_SIM_SOURCES)
VERILATOR_NONCC_OPTS = \
$(RUNTIME_PROFILING_VFLAGS) \
$(RUNTIME_THREADS) \
$(VERILATOR_OPT_FLAGS) \
$(PLATFORM_OPTS) \
-Wno-fatal \
$(TIMESCALE_OPTS) \
$(MAX_WIDTH_OPTS) \
$(PREPROC_DEFINES) \
--top-module $(VLOG_MODEL) \
--vpi \
-f $(sim_common_files) \
$(sim_vsrcs)
#----------------------------------------------------------------------------------------
# gcc configuration/optimization
#----------------------------------------------------------------------------------------
include $(base_dir)/sims/common-sim-flags.mk
VERILATOR_CXXFLAGS = \
$(SIM_CXXFLAGS) \
$(RUNTIME_PROFILING_CFLAGS) \
$(TRACING_CFLAGS) \
-D__STDC_FORMAT_MACROS \
-DTEST_HARNESS=V$(VLOG_MODEL) \
-DVERILATOR \
-include $(build_dir)/$(long_name).plusArgs \
-include $(build_dir)/verilator.h
VERILATOR_LDFLAGS = $(SIM_LDFLAGS)
VERILATOR_CC_OPTS = \
-CFLAGS "$(VERILATOR_CXXFLAGS)" \
-LDFLAGS "$(VERILATOR_LDFLAGS)"
#----------------------------------------------------------------------------------------
# full verilator+gcc opts
#----------------------------------------------------------------------------------------
VERILATOR_OPTS = $(VERILATOR_CC_OPTS) $(VERILATOR_NONCC_OPTS)
#########################################################################################
# verilator build paths and file names
@@ -127,13 +182,13 @@ model_mk_debug = $(model_dir_debug)/V$(VLOG_MODEL).mk
$(model_mk): $(sim_vsrcs) $(sim_common_files) $(EXTRA_SIM_REQS)
rm -rf $(model_dir)
mkdir -p $(model_dir)
$(VERILATOR) $(VERILATOR_OPTS) -o $(sim) -Mdir $(model_dir) -CFLAGS "-include $(model_header)"
$(VERILATOR) $(VERILATOR_OPTS) $(EXTRA_SIM_SOURCES) -o $(sim) -Mdir $(model_dir) -CFLAGS "-include $(model_header)"
touch $@
$(model_mk_debug): $(sim_vsrcs) $(sim_common_files) $(EXTRA_SIM_REQS)
rm -rf $(model_dir_debug)
mkdir -p $(model_dir_debug)
$(VERILATOR) $(VERILATOR_OPTS) -o $(sim_debug) --trace -Mdir $(model_dir_debug) -CFLAGS "-include $(model_header_debug)"
$(VERILATOR) $(VERILATOR_OPTS) $(EXTRA_SIM_SOURCES) -o $(sim_debug) $(TRACING_OPTS) -Mdir $(model_dir_debug) -CFLAGS "-include $(model_header_debug)"
touch $@
#########################################################################################
@@ -150,12 +205,19 @@ $(sim_debug): $(model_mk_debug) $(dramsim_lib)
#########################################################################################
.PRECIOUS: $(output_dir)/%.vpd %.vcd
$(output_dir)/%.vpd: $(output_dir)/% $(sim_debug)
touch $@.vpd
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) -v $@.vcd $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $<.out) | tee $<.log)
rm -f $@.vcd && mkfifo $@.vcd
vcd2vpd $@.vcd $@ > /dev/null &
(set -o pipefail && $(NUMA_PREFIX) $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) -v$@.vcd $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $<.out) | tee $<.log)
#########################################################################################
# general cleanup rule
# general cleanup rules
#########################################################################################
.PHONY: clean
.PHONY: clean clean-sim clean-sim-debug
clean:
rm -rf $(gen_dir) $(sim_prefix)-*
clean-sim:
rm -rf $(model_dir) $(sim)
clean-sim-debug:
rm -rf $(model_dir_debug) $(sim_debug)

View File

@@ -49,7 +49,7 @@ ifdef ENABLE_DROMAJO
EXTRA_SIM_FLAGS += $(DROMAJO_FLAGS)
# CC flags needed for all simulations
EXTRA_SIM_CC_FLAGS += -I$(DROMAJO_DIR)
EXTRA_SIM_CXXFLAGS += -I$(DROMAJO_DIR)
# sourced needed for simulation
EXTRA_SIM_SOURCES += $(DROMAJO_LIB)

View File

@@ -1,23 +1,51 @@
#########################################################################################
# makefile variables shared across multiple makefiles
# - to use the help text, your Makefile should have a 'help' target that just
# prints all the HELP_LINES
#########################################################################################
HELP_COMPILATION_VARIABLES =
HELP_PROJECT_VARIABLES = \
" SUB_PROJECT = use the specific subproject default variables [$(SUB_PROJECT)]" \
" SBT_PROJECT = the SBT project that you should find the classes/packages in [$(SBT_PROJECT)]" \
" MODEL = the top level module of the project in Chisel (normally the harness) [$(MODEL)]" \
" VLOG_MODEL = the top level module of the project in Firrtl/Verilog (normally the harness) [$(VLOG_MODEL)]" \
" MODEL_PACKAGE = the scala package to find the MODEL in [$(MODEL_PACKAGE)]" \
" CONFIG = the configuration class to give the parameters for the project [$(CONFIG)]" \
" CONFIG_PACKAGE = the scala package to find the CONFIG class [$(CONFIG_PACKAGE)]" \
" GENERATOR_PACKAGE = the scala package to find the Generator class in [$(GENERATOR_PACKAGE)]" \
" TB = testbench wrapper over the TestHarness needed to simulate in a verilog simulator [$(TB)]" \
" TOP = top level module of the project (normally the module instantiated by the harness) [$(TOP)]"
#########################################################################################
# variables to invoke the generator
# descriptions:
# SBT_PROJECT = the SBT project that you should find the classes/packages in
# MODEL = the top level module of the project in Chisel (normally the harness)
# VLOG_MODEL = the top level module of the project in Firrtl/Verilog (normally the harness)
# MODEL_PACKAGE = the scala package to find the MODEL in
# CONFIG = the configuration class to give the parameters for the project
# CONFIG_PACKAGE = the scala package to find the CONFIG class
# GENERATOR_PACKAGE = the scala package to find the Generator class in
# TB = wrapper over the TestHarness needed to simulate in a verilog simulator
# TOP = top level module of the project (normally the module instantiated by the harness)
#
# project specific:
# SUB_PROJECT = use the specific subproject default variables
#########################################################################################
HELP_SIMULATION_VARIABLES = \
" BINARY = riscv elf binary that the simulator will run when using the run-binary* targets" \
" VERBOSE_FLAGS = flags used when doing verbose simulation [$(VERBOSE_FLAGS)]"
# include default simulation rules
HELP_COMMANDS = \
" help = display this help" \
" default = compiles non-debug simulator [./$(shell basename $(sim))]" \
" debug = compiles debug simulator [./$(shell basename $(sim_debug))]" \
" clean = remove all debug/non-debug simulators and intermediate files" \
" clean-sim = removes non-debug simulator and simulator-generated files" \
" clean-sim-debug = removes debug simulator and simulator-generated files"
HELP_LINES = "" \
" design specifier variables:" \
" ---------------------------" \
$(HELP_PROJECT_VARIABLES) \
"" \
" compilation variables:" \
" ----------------------" \
$(HELP_COMPILATION_VARIABLES) \
"" \
" simulation variables:" \
" ---------------------" \
$(HELP_SIMULATION_VARIABLES) \
"" \
" some useful general commands:" \
" -----------------------------" \
$(HELP_COMMANDS) \
""
#########################################################################################
# subproject overrides
@@ -140,7 +168,7 @@ override SCALA_BUILDTOOL_DEPS += $(BLOOP_CONFIG_DIR)/TIMESTAMP
# 1) the sed removes a leading {file:<path>} that sometimes needs to be
# provided to SBT when a project but not for bloop.
# 2) Generally, one could could pass '--' to indicate all remaining arguments are
# destined for the scala Main, however a bug in Bloop's argument parsing causes the
# destined for the scala Main, however a bug in Bloop's argument parsing causes the
# --nailgun-port argument to be lost in this case. Workaround this by prefixing
# every main-destined argument with "--args"
define run_scala_main

26
vcs.mk
View File

@@ -11,15 +11,23 @@ endif
CLOCK_PERIOD ?= 1.0
RESET_DELAY ?= 777.7
#----------------------------------------------------------------------------------------
# gcc configuration/optimization
#----------------------------------------------------------------------------------------
include $(base_dir)/sims/common-sim-flags.mk
VCS_CXXFLAGS = $(SIM_CXXFLAGS)
VCS_LDFLAGS = $(SIM_LDFLAGS)
# vcs requires LDFLAGS to not include library names (i.e. -l needs to be separate)
VCS_CC_OPTS = \
-CC "-I$(RISCV)/include" \
-CC "-I$(dramsim_dir)" \
-CC "-std=c++11" \
-CC "$(EXTRA_SIM_CC_FLAGS)"
-CFLAGS "$(VCS_CXXFLAGS)" \
-LDFLAGS "$(filter-out -l%,$(VCS_LDFLAGS))" \
$(filter -l%,$(VCS_LDFLAGS))
VCS_NONCC_OPTS = \
$(dramsim_lib) \
$(RISCV)/lib/libfesvr.a \
-notice \
-line \
+lint=all,noVCDE,noONGS,noUI \
-error=PCWM-L \
-error=noZMMCM \
@@ -27,7 +35,6 @@ VCS_NONCC_OPTS = \
-quiet \
-q \
+rad \
+v2k \
+vcs+lic+wait \
+vc+list \
-f $(sim_common_files) \
@@ -35,10 +42,9 @@ VCS_NONCC_OPTS = \
+v2k +verilog2001ext+.v95+.vt+.vp +libext+.v \
-debug_pp \
+incdir+$(build_dir) \
$(sim_vsrcs) \
+libext+.v
$(sim_vsrcs)
VCS_DEFINE_OPTS = \
PREPROC_DEFINES = \
+define+VCS \
+define+CLOCK_PERIOD=$(CLOCK_PERIOD) \
+define+RESET_DELAY=$(RESET_DELAY) \

View File

@@ -34,7 +34,7 @@ INPUT_CONFS ?= $(if $(filter $(tech_name),nangate45),\
example-asap7.yml)
HAMMER_EXEC ?= example-vlsi
VLSI_TOP ?= $(TOP)
VLSI_HARNESS_DUT_NAME ?= dut
VLSI_HARNESS_DUT_NAME ?= chiptop
VLSI_OBJ_DIR ?= $(vlsi_dir)/build
ifneq ($(CUSTOM_VLOG),)
OBJ_DIR ?= $(VLSI_OBJ_DIR)/custom-$(VLSI_TOP)
@@ -115,15 +115,20 @@ $(SIM_CONF): $(VLSI_RTL) $(HARNESS_FILE) $(HARNESS_SMEMS_FILE) $(sim_common_file
done
echo " options_meta: 'append'" >> $@
echo " defines:" >> $@
for x in $(subst +define+,,$(VCS_DEFINE_OPTS)); do \
for x in $(subst +define+,,$(PREPROC_DEFINES)); do \
echo ' - "'$$x'"' >> $@; \
done
echo " defines_meta: 'append'" >> $@
echo " compiler_opts:" >> $@
for x in $(filter-out "",$(filter-out -CC,$(VCS_CC_OPTS))); do \
echo " compiler_cc_opts:" >> $@
for x in $(filter-out "",$(VCS_CXXFLAGS)); do \
echo ' - "'$$x'"' >> $@; \
done
echo " compiler_opts_meta: 'append'" >> $@
echo " compiler_cc_opts_meta: 'append'" >> $@
echo " compiler_ld_opts:" >> $@
for x in $(filter-out "",$(VCS_LDFLAGS)); do \
echo ' - "'$$x'"' >> $@; \
done
echo " compiler_ld_opts_meta: 'append'" >> $@
echo " execution_flags_prepend: ['$(PERMISSIVE_ON)']" >> $@
echo " execution_flags_append: ['$(PERMISSIVE_OFF)']" >> $@
echo " execution_flags:" >> $@