Merge remote-tracking branch 'origin/main' into use-fat-jar

This commit is contained in:
abejgonzalez
2023-05-17 18:12:21 -07:00
176 changed files with 4080 additions and 2798 deletions

View File

@@ -15,7 +15,7 @@ runs:
conda env remove -n $env
done
fi
IS_NUMBER_REGEX='[0-9]+$'
IS_NUMBER_REGEX='^[0-9]+$'
conda env list | awk '{print $1}' | tail -n +4 | while read envname; do
ENV_DATE=$(echo $envname | sed "s/cy-[[:digit:]]\+-\(.*\)-\(riscv\|esp\)-tools/\1/")
if ! [[ $ENV_DATE =~ $IS_NUMBER_REGEX ]]; then

View File

@@ -45,7 +45,7 @@ search () {
done
}
submodules=("cva6" "boom" "ibex" "hwacha" "icenet" "nvdla" "rocket-chip" "sha3" "sifive-blocks" "sifive-cache" "testchipip" "riscv-sodor" "mempress")
submodules=("cva6" "boom" "ibex" "gemmini" "hwacha" "icenet" "nvdla" "rocket-chip" "sha3" "sifive-blocks" "sifive-cache" "testchipip" "riscv-sodor" "mempress")
dir="generators"
branches=("master" "main" "dev")
search

View File

@@ -33,7 +33,7 @@ REMOTE_COURSIER_CACHE=$REMOTE_WORK_DIR/.coursier-cache
# key value store to get the build groups
declare -A grouping
grouping["group-cores"]="chipyard-cva6 chipyard-ibex chipyard-rocket chipyard-hetero chipyard-boom chipyard-sodor chipyard-digitaltop chipyard-multiclock-rocket chipyard-nomem-scratchpad chipyard-spike chipyard-clone"
grouping["group-peripherals"]="chipyard-dmirocket chipyard-spiflashwrite chipyard-mmios chipyard-nocores chipyard-manyperipherals"
grouping["group-peripherals"]="chipyard-dmirocket chipyard-dmiboom chipyard-spiflashwrite chipyard-mmios chipyard-nocores chipyard-manyperipherals chipyard-chiplike"
grouping["group-accels"]="chipyard-mempress chipyard-sha3 chipyard-hwacha chipyard-gemmini chipyard-manymmioaccels"
grouping["group-constellation"]="chipyard-constellation"
grouping["group-tracegen"]="tracegen tracegen-boom"
@@ -50,13 +50,15 @@ mapping["chipyard-digitaltop"]=" TOP=DigitalTop"
mapping["chipyard-manymmioaccels"]=" CONFIG=ManyMMIOAcceleratorRocketConfig"
mapping["chipyard-hetero"]=" CONFIG=LargeBoomAndRocketConfig"
mapping["chipyard-boom"]=" CONFIG=MediumBoomCosimConfig"
mapping["chipyard-spike"]=" CONFIG=SpikeFastUARTConfig EXTRA_SIM_FLAGS='+spike-ipc=10'"
mapping["chipyard-dmiboom"]=" CONFIG=dmiMediumBoomCosimConfig"
mapping["chipyard-spike"]=" CONFIG=SpikeConfig EXTRA_SIM_FLAGS='+spike-ipc=10'"
mapping["chipyard-hwacha"]=" CONFIG=HwachaRocketConfig"
mapping["chipyard-gemmini"]=" CONFIG=GemminiRocketConfig"
mapping["chipyard-cva6"]=" CONFIG=CVA6Config"
mapping["chipyard-ibex"]=" CONFIG=IbexConfig"
mapping["chipyard-spiflashwrite"]=" CONFIG=SmallSPIFlashRocketConfig EXTRA_SIM_FLAGS='+spiflash0=${LOCAL_CHIPYARD_DIR}/tests/spiflash.img'"
mapping["chipyard-manyperipherals"]=" CONFIG=ManyPeripheralsRocketConfig EXTRA_SIM_FLAGS='+spiflash0=${LOCAL_CHIPYARD_DIR}/tests/spiflash.img'"
mapping["chipyard-chiplike"]=" CONFIG=ChipLikeQuadRocketConfig MODEL=FlatTestHarness MODEL_PACKAGE=chipyard.example verilog"
mapping["chipyard-cloneboom"]=" CONFIG=Cloned64MegaBoomConfig verilog"
mapping["chipyard-nocores"]=" CONFIG=NoCoresConfig verilog"
mapping["tracegen"]=" CONFIG=NonBlockingTraceGenL2Config"

View File

@@ -16,8 +16,6 @@ source $SCRIPT_DIR/defaults.sh
cd $REMOTE_CHIPYARD_DIR
./scripts/init-submodules-no-riscv-tools.sh --force
./scripts/init-fpga.sh
# Constellation can run without espresso, but this improves
# elaboration time drastically

View File

@@ -33,11 +33,16 @@ case $1 in
run_bmark ${mapping[$1]}
;;
chipyard-dmirocket)
run_bmark ${mapping[$1]}
$LOCAL_CHIPYARD_DIR/scripts/generate-ckpt.sh -b $RISCV/riscv64-unknown-elf/share/riscv-tests/benchmarks/dhrystone.riscv -i 10000
make -C $LOCAL_SIM_DIR $DISABLE_SIM_PREREQ ${mapping[$1]} run-binary LOADARCH=$PWD/dhrystone.riscv.0x80000000.10000.loadarch
;;
chipyard-boom)
run_bmark ${mapping[$1]}
;;
chipyard-dmiboom)
$LOCAL_CHIPYARD_DIR/scripts/generate-ckpt.sh -b $RISCV/riscv64-unknown-elf/share/riscv-tests/benchmarks/dhrystone.riscv -i 10000
make -C $LOCAL_SIM_DIR $DISABLE_SIM_PREREQ ${mapping[$1]} run-binary LOADARCH=$PWD/dhrystone.riscv.0x80000000.10000.loadarch
;;
chipyard-spike)
run_bmark ${mapping[$1]}
;;

View File

@@ -390,6 +390,35 @@ jobs:
##########################################################################
chipyard-spike-gemmini-run-tests:
name: chipyard-spike-gemmini-run-tests
needs: prepare-chipyard-accels # technically doesn't depend on RTL but should be after the build.sh for Gemmini
runs-on: ferry
steps:
- name: Delete old checkout
run: |
ls -alh .
rm -rf ${{ github.workspace }}/* || true
rm -rf ${{ github.workspace }}/.* || true
ls -alh .
- name: Checkout
uses: actions/checkout@v3
- name: Git workaround
uses: ./.github/actions/git-workaround
- name: Create conda env
uses: ./.github/actions/create-conda-env
- name: Build Gemmini FireMarshal
run: |
conda activate ${{ env.conda-env-name-no-time }}-$(date --date "${{ env.workflow-timestamp }}" +%Y%m%d)-riscv-tools
cd ${{ github.workspace }} && ./scripts/init-submodules-no-riscv-tools.sh --force
cd ${{ github.workspace }} && source ./scripts/fix-open-files.sh
git submodule update --init software/firemarshal && cd software/firemarshal && ./init-submodules.sh
cd ${{ github.workspace }}/generators/gemmini/software && ${{ github.workspace }}/software/firemarshal/marshal -v -d build gemmini-smoke.json
- name: Running Gemmini FireMarshal smoke test
run: |
conda activate ${{ env.conda-env-name-no-time }}-$(date --date "${{ env.workflow-timestamp }}" +%Y%m%d)-riscv-tools
cd ${{ github.workspace }}/generators/gemmini/software && ${{ github.workspace }}/software/firemarshal/marshal -v -d launch -s gemmini-smoke.json
chipyard-rocket-run-tests:
name: chipyard-rocket-run-tests
needs: prepare-chipyard-cores
@@ -574,6 +603,29 @@ jobs:
group-key: "group-peripherals"
project-key: "chipyard-dmirocket"
chipyard-dmiboom-run-tests:
name: chipyard-dmiboom-run-tests
needs: prepare-chipyard-peripherals
runs-on: self-hosted
steps:
- name: Delete old checkout
run: |
ls -alh .
rm -rf ${{ github.workspace }}/* || true
rm -rf ${{ github.workspace }}/.* || true
ls -alh .
- name: Checkout
uses: actions/checkout@v3
- name: Git workaround
uses: ./.github/actions/git-workaround
- name: Create conda env
uses: ./.github/actions/create-conda-env
- name: Run tests
uses: ./.github/actions/run-tests
with:
group-key: "group-peripherals"
project-key: "chipyard-dmiboom"
chipyard-spiflashwrite-run-tests:
name: chipyard-spiflashwrite-run-tests
needs: prepare-chipyard-peripherals
@@ -915,6 +967,7 @@ jobs:
chipyard-cva6-run-tests,
chipyard-ibex-run-tests,
chipyard-sodor-run-tests,
chipyard-dmiboom-run-tests,
chipyard-dmirocket-run-tests,
chipyard-spiflashwrite-run-tests,
chipyard-manyperipherals-run-tests,

9
.gitmodules vendored
View File

@@ -73,9 +73,6 @@
[submodule "fpga/fpga-shells"]
path = fpga/fpga-shells
url = https://github.com/chipsalliance/rocket-chip-fpga-shells.git
[submodule "tools/api-config-chipsalliance"]
path = tools/api-config-chipsalliance
url = https://github.com/chipsalliance/api-config-chipsalliance.git
[submodule "tools/rocket-dsp-utils"]
path = tools/rocket-dsp-utils
url = https://github.com/ucb-bar/rocket-dsp-utils
@@ -121,3 +118,9 @@
[submodule "generators/mempress"]
path = generators/mempress
url = https://github.com/ucb-bar/mempress.git
[submodule "tools/cde"]
path = tools/cde
url = https://github.com/chipsalliance/cde.git
[submodule "software/embench/embench-iot"]
path = software/embench/embench-iot
url = https://github.com/embench/embench-iot.git

View File

@@ -2,6 +2,34 @@
This changelog follows the format defined here: https://keepachangelog.com/en/1.0.0/
## [1.9.1] - 2023-04-21
Various fixes for Linux boot, More Chip/bringup examples, Chisel 3.5.6 bump
### Added
* QoL improvement to IOBinders + custom ChipTop example by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1399
* PLL integration example + FlatChipTop/TestHarness by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1427
* Bump TestChipIp to improve default serial_tl behavior by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1435
* Bump testchipip to standardize TL serdesser bundle params by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1446
* HarnessBinder asserts to catch bad clock generation by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1460
### Changed
* New Scala-based Config Finder by @abejgonzalez in https://github.com/ucb-bar/chipyard/pull/1424
* Bump to latest rocket-chip/chisel3.5.6 by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1411
* Resolve merge conflicts in chisel3.5.6 bump by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1430
* bump testchipip by @joey0320 in https://github.com/ucb-bar/chipyard/pull/1434
* ADD: improve Makefile in tests/, add explicit arch flags by @T-K-233 in https://github.com/ucb-bar/chipyard/pull/1439
* Various submodule bumps by @abejgonzalez in https://github.com/ucb-bar/chipyard/pull/1448
* Support not instantiating tile reset/clock contorl features by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1459
### Fixed
* Various improvements and fixes by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1420
* Ensure conda cleanup regex properly filters out non-numeric chars by @abejgonzalez in https://github.com/ucb-bar/chipyard/pull/1425
* Fix ChipLikeQuadRocketConfig crossing by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1436
* Uniquify module names that are common to Top & Model by @joey0320 in https://github.com/ucb-bar/chipyard/pull/1442
* Support for no-bootROM systems by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1458
* Support for no-UART systems by @jerryz123 in https://github.com/ucb-bar/chipyard/pull/1457
## [1.9.0] - 2023-03-23
Faster FIRRTL build support work CIRCT. New software support for RISC-V GCC12 and Linux 6.2. Various bumps and fixes of all submodules.

View File

@@ -2,9 +2,6 @@
# Chipyard Framework [![Test](https://github.com/ucb-bar/chipyard/actions/workflows/chipyard-run-tests.yml/badge.svg)](https://github.com/ucb-bar/chipyard/actions)
| We're running the First FireSim and Chipyard User/Developer Workshop at ASPLOS 2023 on March 26, 2023! This workshop will feature a full-day of submitted talks from users and developers in the FireSim and Chipyard community. Learn more and **submit your work** on the [2023 Workshop Page](https://fires.im/workshop-2023/)! |
|-----|
## Quick Links
* **Stable Documentation**: https://chipyard.readthedocs.io/

View File

@@ -82,7 +82,7 @@ def isolateAllTests(tests: Seq[TestDefinition]) = tests map { test =>
new Group(test.name, Seq(test), SubProcess(options))
} toSeq
val chiselVersion = "3.5.5"
val chiselVersion = "3.5.6"
lazy val chiselSettings = Seq(
libraryDependencies ++= Seq("edu.berkeley.cs" %% "chisel3" % chiselVersion,
@@ -118,11 +118,8 @@ lazy val rocketMacros = (project in rocketChipDir / "macros")
)
)
lazy val rocketConfig = (project in rocketChipDir / "api-config-chipsalliance/build-rules/sbt")
.settings(commonSettings)
lazy val rocketchip = freshProject("rocketchip", rocketChipDir)
.dependsOn(hardfloat, rocketMacros, rocketConfig)
.dependsOn(hardfloat, rocketMacros, cde)
.settings(commonSettings)
.settings(chiselSettings)
.settings(
@@ -158,7 +155,12 @@ lazy val chipyard = (project in file("generators/chipyard"))
gemmini, icenet, tracegen, cva6, nvdla, sodor, ibex, fft_generator,
constellation, mempress)
.settings(libraryDependencies ++= rocketLibDeps.value)
.settings(commonSettings)
.settings(
libraryDependencies ++= Seq(
"org.reflections" % "reflections" % "0.10.2"
)
)
.settings(commonSettings)
lazy val mempress = (project in file("generators/mempress"))
.dependsOn(rocketchip, midasTargetUtils)
@@ -254,16 +256,12 @@ lazy val dsptools = freshProject("dsptools", file("./tools/dsptools"))
"org.scalacheck" %% "scalacheck" % "1.14.3" % "test",
))
lazy val `api-config-chipsalliance` = freshProject("api-config-chipsalliance", file("./tools/api-config-chipsalliance"))
.settings(
commonSettings,
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.0.+" % "test",
"org.scalacheck" %% "scalacheck" % "1.14.3" % "test",
))
lazy val cde = (project in file("tools/cde"))
.settings(commonSettings)
.settings(Compile / scalaSource := baseDirectory.value / "cde/src/chipsalliance/rocketchip")
lazy val `rocket-dsp-utils` = freshProject("rocket-dsp-utils", file("./tools/rocket-dsp-utils"))
.dependsOn(rocketchip, `api-config-chipsalliance`, dsptools)
.dependsOn(rocketchip, cde, dsptools)
.settings(libraryDependencies ++= rocketLibDeps.value)
.settings(commonSettings)

View File

@@ -48,7 +48,7 @@ HELP_COMMANDS += \
" firrtl = generate intermediate firrtl files from chisel elaboration" \
" run-tests = run all assembly and benchmark tests" \
" launch-sbt = start sbt terminal" \
" find-config-fragments = list all config. fragments"
#########################################################################################
# include additional subproject make fragments
@@ -239,32 +239,28 @@ $(SFC_MFC_TARGETS) &: $(BTL_CLASSPATH_TARGETS) $(FIRRTL_FILE) $(FINAL_ANNO_FILE)
$(SED) -i 's/.*/& /' $(MFC_SMEMS_CONF) # need trailing space for SFC macrocompiler
# DOC include end: FirrtlCompiler
$(TOP_MODS_FILELIST) $(MODEL_MODS_FILELIST) $(ALL_MODS_FILELIST) $(BB_MODS_FILELIST) &: $(MFC_MODEL_HRCHY_JSON) $(MFC_FILELIST) $(MFC_BB_MODS_FILELIST)
$(base_dir)/scripts/split-module-files.py \
$(TOP_MODS_FILELIST) $(MODEL_MODS_FILELIST) $(ALL_MODS_FILELIST) $(BB_MODS_FILELIST) $(MFC_MODEL_HRCHY_JSON_UNIQUIFIED) &: $(MFC_MODEL_HRCHY_JSON) $(MFC_TOP_HRCHY_JSON) $(MFC_FILELIST) $(MFC_BB_MODS_FILELIST)
$(base_dir)/scripts/uniquify-module-names.py \
--model-hier-json $(MFC_MODEL_HRCHY_JSON) \
--top-hier-json $(MFC_TOP_HRCHY_JSON) \
--in-all-filelist $(MFC_FILELIST) \
--dut $(TOP) \
--model $(MODEL) \
--target-dir $(GEN_COLLATERAL_DIR) \
--out-dut-filelist $(TOP_MODS_FILELIST) \
--out-model-filelist $(MODEL_MODS_FILELIST) \
--in-all-filelist $(MFC_FILELIST) \
--target-dir $(GEN_COLLATERAL_DIR)
--out-model-hier-json $(MFC_MODEL_HRCHY_JSON_UNIQUIFIED) \
--gcpath $(GEN_COLLATERAL_DIR)
$(SED) -e 's;^;$(GEN_COLLATERAL_DIR)/;' $(MFC_BB_MODS_FILELIST) > $(BB_MODS_FILELIST)
$(SED) -i 's/\.\///' $(TOP_MODS_FILELIST)
$(SED) -i 's/\.\///' $(MODEL_MODS_FILELIST)
$(SED) -i 's/\.\///' $(BB_MODS_FILELIST)
sort -u $(TOP_MODS_FILELIST) $(MODEL_MODS_FILELIST) $(BB_MODS_FILELIST) > $(ALL_MODS_FILELIST)
$(TOP_BB_MODS_FILELIST) $(MODEL_BB_MODS_FILELIST) &: $(BB_MODS_FILELIST) $(MFC_TOP_HRCHY_JSON) $(FINAL_ANNO_FILE)
$(base_dir)/scripts/split-bb-files.py \
--in-bb-f $(BB_MODS_FILELIST) \
--in-top-hrchy-json $(MFC_TOP_HRCHY_JSON) \
--in-anno-json $(FINAL_ANNO_FILE) \
--out-top-bb-f $(TOP_BB_MODS_FILELIST) \
--out-model-bb-f $(MODEL_BB_MODS_FILELIST)
$(TOP_SMEMS_CONF) $(MODEL_SMEMS_CONF) &: $(MFC_SMEMS_CONF) $(MFC_MODEL_HRCHY_JSON)
$(TOP_SMEMS_CONF) $(MODEL_SMEMS_CONF) &: $(MFC_SMEMS_CONF) $(MFC_MODEL_HRCHY_JSON_UNIQUIFIED)
$(base_dir)/scripts/split-mems-conf.py \
--in-smems-conf $(MFC_SMEMS_CONF) \
--in-model-hrchy-json $(MFC_MODEL_HRCHY_JSON) \
--in-model-hrchy-json $(MFC_MODEL_HRCHY_JSON_UNIQUIFIED) \
--dut-module-name $(TOP) \
--model-module-name $(MODEL) \
--out-dut-smems-conf $(TOP_SMEMS_CONF) \
@@ -284,7 +280,7 @@ $(MODEL_SMEMS_FILE) $(MODEL_SMEMS_FIR) &: $(BTL_CLASSPATH_TARGETS) $(MODEL_SMEMS
# note: {MODEL,TOP}_BB_MODS_FILELIST is added as a req. so that the files get generated,
# however it is really unneeded since ALL_MODS_FILELIST includes all BB files
########################################################################################
$(sim_common_files): $(sim_files) $(ALL_MODS_FILELIST) $(TOP_SMEMS_FILE) $(MODEL_SMEMS_FILE) $(TOP_BB_MODS_FILELIST) $(MODEL_BB_MODS_FILELIST)
$(sim_common_files): $(sim_files) $(ALL_MODS_FILELIST) $(TOP_SMEMS_FILE) $(MODEL_SMEMS_FILE) $(BB_MODS_FILELIST)
sort -u $(sim_files) $(ALL_MODS_FILELIST) | grep -v '.*\.\(svh\|h\)$$' > $@
echo "$(TOP_SMEMS_FILE)" >> $@
echo "$(MODEL_SMEMS_FILE)" >> $@
@@ -304,6 +300,11 @@ check-binary:
ifeq (,$(BINARY))
$(error BINARY variable is not set. Set it to the simulation binary)
endif
ifneq (none,$(BINARY))
ifeq ("$(wildcard $(BINARY))","")
$(error BINARY=$(BINARY) not found)
endif
endif
# allow you to override sim prereq
ifeq (,$(BREAK_SIM_PREREQ))
@@ -321,34 +322,23 @@ run-binary-fast: $(SIM_PREREQ) check-binary | $(output_dir)
# run simulator with as much debug info as possible
run-binary-debug: $(SIM_DEBUG_PREREQ) check-binary | $(output_dir)
ifneq (none,$(BINARY))
riscv64-unknown-elf-objdump -D $(BINARY) > $(sim_out_name).dump
endif
(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
#########################################################################################
# helper rules to run simulator with fast loadmem via hex files
# helper rules to run simulator with fast loadmem
# LEGACY - use LOADMEM=1 instead
#########################################################################################
$(binary_hex): $(firstword $(BINARY)) | $(output_dir)
$(base_dir)/scripts/smartelf2hex.sh $(firstword $(BINARY)) > $(binary_hex)
run-binary-hex: check-binary
run-binary-hex: $(SIM_PREREQ) $(binary_hex) | $(output_dir)
run-binary-hex: run-binary
run-binary-hex: override LOADMEM_ADDR = 80000000
run-binary-hex: override LOADMEM = $(binary_hex)
run-binary-hex: override SIM_FLAGS += +loadmem=$(LOADMEM) +loadmem_addr=$(LOADMEM_ADDR)
run-binary-debug-hex: check-binary
run-binary-debug-hex: $(SIM_DEBUG_REREQ) $(binary_hex) | $(output_dir)
run-binary-hex: override SIM_FLAGS += +loadmem=$(BINARY)
run-binary-debug-hex: run-binary-debug
run-binary-debug-hex: override LOADMEM_ADDR = 80000000
run-binary-debug-hex: override LOADMEM = $(binary_hex)
run-binary-debug-hex: override SIM_FLAGS += +loadmem=$(LOADMEM) +loadmem_addr=$(LOADMEM_ADDR)
run-binary-fast-hex: check-binary
run-binary-fast-hex: $(SIM_PREREQ) $(binary_hex) | $(output_dir)
run-binary-debug-hex: override SIM_FLAGS += +loadmem=$(BINARY)
run-binary-fast-hex: run-binary-fast
run-binary-fast-hex: override LOADMEM_ADDR = 80000000
run-binary-fast-hex: override LOADMEM = $(binary_hex)
run-binary-fast-hex: override SIM_FLAGS += +loadmem=$(LOADMEM) +loadmem_addr=$(LOADMEM_ADDR)
run-binary-fast-hex: override SIM_FLAGS += +loadmem=$(BINARY)
#########################################################################################
# run assembly/benchmarks rules
@@ -398,13 +388,9 @@ define \n
endef
CONFIG_FRAG_LEVELS ?= 3
.PHONY: find-config-fragments
find-config-fragments: private IN_F := $(shell mktemp -d -t cy-XXXXXXXX)/scala_files.f
find-config-fragments: $(SCALA_SOURCES)
@$(foreach file,$(SCALA_SOURCES),echo $(file) >> $(IN_F)${\n})
$(base_dir)/scripts/config-finder.py -l $(CONFIG_FRAG_LEVELS) $(IN_F)
@rm -rf $(dir $(IN_F))
find-config-fragments:
$(call run_scala_main,chipyard,chipyard.ConfigFinder,)
.PHONY: help
help:

View File

@@ -89,7 +89,7 @@ dependencies:
- graphviz
- expect
- dtc
- verilator==4.226
- verilator==5.008
- screen
- elfutils
- libdwarf-dev==0.0.0.20190110_28_ga81397fc4 # from ucb-bar channel - using mainline libdwarf-feedstock
@@ -103,7 +103,7 @@ dependencies:
- sty
- open_pdks.sky130a
- pip:
- hammer-vlsi[asap7]==1.1.0
- hammer-vlsi[asap7]==1.1.1
# doc requirements
- sphinx
@@ -131,7 +131,7 @@ dependencies:
- pytest-mock
- moto
- mypy
- s3fs
- s3fs==0.4.2
- aiohttp
- pip:
- sure

View File

@@ -0,0 +1,39 @@
.. _checkpointing:
Architectural Checkpoints
=========================
Chipyard supports generating architectural checkpoints using Spike.
These checkpoints contain a snapshot of the architectural state of a RISC-V SoC at some point in the execution of a program.
The checkpoints include the contents of cacheable memory, core architectural registers, and core CSRs.
RTL simulations of SoCs can resume execution from checkpoints after restoring the architectural state.
.. note::
Currently, only checkpoints of single-core systems are supported
Generating Checkpoints
------------------------
``scripts/generate-ckpt.sh`` is a script that runs spike with the right commands to generate an architectural checkpoint
``scripts/generate-ckpt.sh -h`` lists options for checkpoint generation.
Example: run the ``hello.riscv`` binary for 1000 instructions before generating a checkpoint.
This should produce a directory named ``hello.riscv.0x80000000.1000.loadarch``
.. code::
scripts/generate-ckpt.sh -b tests/hello.riscv -i 1000
Loading Checkpoints in RTL Simulation
--------------------------------------
Checkpoints can be loaded in RTL simulations with the ``LOADARCH`` flag.
The target config **MUST** use dmi-based bringup (as opposed to the default TSI-based bringup), and support fast ``LOADMEM``.
The target config should also match the architectural configuration of however spike was configured when generating the checkpoint.
.. code::
cd sims/vcs
make CONFIG=dmiRocketConfig run-binary LOADARCH=../../hello.riscv.0x80000000.1000.loadarch

View File

@@ -47,12 +47,12 @@ Using the Tethered Serial Interface (TSI)
By default, Chipyard uses the Tethered Serial Interface (TSI) to communicate with the DUT.
TSI protocol is an implementation of HTIF that is used to send commands to the RISC-V DUT.
These TSI commands are simple R/W commands that are able to access the DUT's memory space.
During simulation, the host sends TSI commands to a simulation stub in the test harness called ``SimSerial``
(C++ class) that resides in a ``SimSerial`` Verilog module (both are located in the ``generators/testchipip``
During simulation, the host sends TSI commands to a simulation stub in the test harness called ``SimTSI``
(C++ class) that resides in a ``SimTSI`` Verilog module (both are located in the ``generators/testchipip``
project).
This ``SimSerial`` Verilog module then sends the TSI command recieved by the simulation stub
This ``SimTSI`` Verilog module then sends the TSI command recieved by the simulation stub
to an adapter that converts the TSI command into a TileLink request.
This conversion is done by the ``SerialAdapter`` module (located in the ``generators/testchipip`` project).
This conversion is done by the ``TSIToTileLink`` module (located in the ``generators/testchipip`` project).
After the transaction is converted to TileLink, the ``TLSerdesser`` (located in ``generators/testchipip``) serializes the
transaction and sends it to the chip (this ``TLSerdesser`` is sometimes also referred to as a digital serial-link or SerDes).
Once the serialized transaction is received on the chip, it is deserialized and masters a TileLink bus on the chip
@@ -76,7 +76,7 @@ simulation stub called ``SimDTM`` (C++ class) that resides in a ``SimDTM`` Veril
sends the DMI command recieved by the simulation stub into the DUT which then converts the DMI
command into a TileLink request. This conversion is done by the DTM named ``DebugModule`` in the ``generators/rocket-chip`` project.
When the DTM receives the program to load, it starts to write the binary byte-wise into memory.
This is considerably slower than the TSI protocol communication pipeline (i.e. ``SimSerial``/``SerialAdapter``/TileLink)
This is considerably slower than the TSI protocol communication pipeline (i.e. ``SimTSI``/``TSIToTileLink``/TileLink)
which directly writes the program binary to memory.
Starting the TSI or DMI Simulation
@@ -206,13 +206,17 @@ This type of simulation setup is done in the following multi-clock configuration
:start-after: DOC include start: MulticlockAXIOverSerialConfig
:end-before: DOC include end: MulticlockAXIOverSerialConfig
Bringup Setup of the Example Test Chip after Tapeout
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Softcore-driven Bringup Setup of the Example Test Chip after Tapeout
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. warning::
Bringing up test chips with a FPGA softcore as described here is discouraged.
An alternative approach using the FPGA to "bridge" between a host computer and the test chip is the preferred approach.
Assuming this example test chip is taped out and now ready to be tested, we can communicate with the chip using this serial-link.
For example, a common test setup used at Berkeley to evaluate Chipyard-based test-chips includes an FPGA running a RISC-V soft-core that is able to speak to the DUT (over an FMC).
This RISC-V soft-core would serve as the host of the test that will run on the DUT.
This is done by the RISC-V soft-core running FESVR, sending TSI commands to a ``SerialAdapter`` / ``TLSerdesser`` programmed on the FPGA.
This is done by the RISC-V soft-core running FESVR, sending TSI commands to a ``TSIToTileLink`` / ``TLSerdesser`` programmed on the FPGA.
Once the commands are converted to serialized TileLink, then they can be sent over some medium to the DUT
(like an FMC cable or a set of wires connecting FPGA outputs to the DUT board).
Similar to simulation, if the chip requests offchip memory, it can then send the transaction back over the serial-link.
@@ -222,4 +226,4 @@ The following image shows this flow:
.. image:: ../_static/images/chip-bringup.png
In fact, this exact type of bringup setup is what the following section discusses:
:ref:`Prototyping/VCU118:Introduction to the Bringup Design`.
:ref:_legacy-vcu118-bringup.

View File

@@ -18,12 +18,12 @@ for a new clock domain.
This is useful for simulating systems in which modules in the harness have independent clock domains
from the DUT.
Requests for a harness clock is done by the ``HarnessClockInstantiator`` class in ``generators/chipyard/src/main/scala/TestHarness.scala``.
Requests for a harness clock is done by the ``HarnessClockInstantiator`` class in ``generators/chipyard/src/main/scala/harness/TestHarness.scala``.
This class is accessed in harness components by referencing the Rocket Chip parameters key ``p(HarnessClockInstantiatorKey)``.
Then you can request a clock and syncronized reset at a particular frequency by invoking the ``requestClockBundle`` function.
Take the following example:
.. literalinclude:: ../../generators/chipyard/src/main/scala/HarnessBinders.scala
.. literalinclude:: ../../generators/chipyard/src/main/scala/harness/HarnessBinders.scala
:language: scala
:start-after: DOC include start: HarnessClockInstantiatorEx
:end-before: DOC include end: HarnessClockInstantiatorEx

View File

@@ -2,24 +2,24 @@ Accessing Scala Resources
===============================
A simple way to copy over a source file to the build directory to be used for a simulation compile or VLSI flow is to use the ``addResource`` function given by FIRRTL.
An example of its use can be seen in `generators/testchipip/src/main/scala/SerialAdapter.scala <https://github.com/ucb-bar/testchipip/blob/master/src/main/scala/SerialAdapter.scala>`_.
An example of its use can be seen in `generators/testchipip/src/main/scala/SimTSI.scala <https://github.com/ucb-bar/testchipip/blob/master/src/main/scala/SimTSI.scala>`_.
Here is the example inlined:
.. code-block:: scala
class SimSerial(w: Int) extends BlackBox with HasBlackBoxResource {
class SimTSI extends BlackBox with HasBlackBoxResource {
val io = IO(new Bundle {
val clock = Input(Clock())
val reset = Input(Bool())
val serial = Flipped(new SerialIO(w))
val tsi = Flipped(new TSIIO)
val exit = Output(Bool())
})
addResource("/testchipip/vsrc/SimSerial.v")
addResource("/testchipip/csrc/SimSerial.cc")
addResource("/testchipip/vsrc/SimTSI.v")
addResource("/testchipip/csrc/SimTSI.cc")
}
In this example, the ``SimSerial`` files will be copied from a specific folder (in this case the ``path/to/testchipip/src/main/resources/testchipip/...``) to the build folder.
In this example, the ``SimTSI`` files will be copied from a specific folder (in this case the ``path/to/testchipip/src/main/resources/testchipip/...``) to the build folder.
The ``addResource`` path retrieves resources from the ``src/main/resources`` directory.
So to get an item at ``src/main/resources/fileA.v`` you can use ``addResource("/fileA.v")``.
However, one caveat of this approach is that to retrieve the file during the FIRRTL compile, you must have that project in the FIRRTL compiler's classpath.

View File

@@ -18,6 +18,13 @@ The ``IOBinders`` are responsible for instantiating the IO cells for ``ChipTop``
The ``HarnessBinders`` are responsible for instantiating test harness collateral that connects to the ``ChipTop`` ports.
Most types of devices and testing collateral can be instantiated using custom ``IOBinders`` and ``HarnessBinders``.
Custom ChipTops
^^^^^^^^^^^^^^^^^^^^^^^^^
The default standard ``ChipTop`` provides a mimimal, barebones template for ``IOBinders`` to generate IOCells around ``DigitalTop`` traits.
For tapeouts, integrating Analog IP, or other non-standard use cases, Chipyard supports specifying a custom ``ChipTop`` using the ``BuildTop`` key.
An example of a custom ChipTop which uses non-standard IOCells is provided in `generators/chipyard/src/main/scala/example/CustomChipTop.scala <https://github.com/ucb-bar/chipyard/blob/main/generators/chipyard/src/main/scala/example/CustomChipTop.scala>`__
System/DigitalTop
-------------------------

View File

@@ -16,3 +16,4 @@ They expect you to know about Chisel, Parameters, configs, etc.
CDEs
Harness-Clocks
Managing-Published-Scala-Dependencies
Architectural-Checkpoints

View File

@@ -83,8 +83,8 @@ This example shows the Chipyard default top that composes multiple traits togeth
:end-before: DOC include end: DigitalTop
There are two "cakes" or mixins here. One for the lazy module (ex. ``CanHavePeripherySerial``) and one for the lazy module
implementation (ex. ``CanHavePeripherySerialModuleImp`` where ``Imp`` refers to implementation). The lazy module defines
There are two "cakes" or mixins here. One for the lazy module (ex. ``CanHavePeripheryTLSerial``) and one for the lazy module
implementation (ex. ``CanHavePeripheryTLSerialModuleImp`` where ``Imp`` refers to implementation). The lazy module defines
all the logical connections between generators and exchanges configuration information among them, while the
lazy module implementation performs the actual Chisel RTL elaboration.
@@ -93,19 +93,17 @@ In the ``DigitalTop`` example class, the "outer" ``DigitalTop`` instantiates the
of the module until all logical connections are determined and all configuration information is exchanged.
The ``System`` outer base class, as well as the
``CanHavePeriphery<X>`` outer traits contain code to perform high-level logical
connections. For example, the ``CanHavePeripherySerial`` outer trait contains code
to optionally lazily instantiate the ``SerialAdapter``, and connect the ``SerialAdapter``'s
connections. For example, the ``CanHavePeripheryTLSerial`` outer trait contains code
to optionally lazily instantiate the ``TLSerdesser``, and connect the ``TLSerdesser`` 's
TileLink node to the Front bus.
The ``ModuleImp`` classes and traits perform elaboration of real RTL.
For example, the ``CanHavePeripherySerialModuleImp`` trait optionally physically connects
the ``SerialAdapter`` module, and instantiates queues.
In the test harness, the SoC is elaborated with
``val dut = p(BuildTop)(p)``.
After elaboration, the system submodule of ``ChipTop`` will be a ``DigitalTop`` module, which contains a
``SerialAdapter`` module (among others), if the config specified for that block to be instantiated.
``TLSerdesser`` module (among others), if the config specified for that block to be instantiated.
From a high level, classes which extend ``LazyModule`` *must* reference
their module implementation through ``lazy val module``, and they
@@ -116,7 +114,7 @@ other normal modules OR lazy modules (for nested Diplomacy
graphs, for example).
The naming convention for an additive mixin or trait is ``CanHave<YourMixin>``.
This is shown in the ``Top`` class where things such as ``CanHavePeripherySerial`` connect a RTL component to a bus and expose signals to the top-level.
This is shown in the ``Top`` class where things such as ``CanHavePeripheryTLSerial`` connect a RTL component to a bus and expose signals to the top-level.
Additional References
---------------------------

View File

@@ -31,7 +31,7 @@ Like ``IOBinders``, ``HarnessBinders`` are defined using macros (``OverrideHarne
For exmaple, the ``WithUARTAdapter`` will connect the UART SW display adapter to the ports generated by the ``WithUARTIOCells`` described earlier, if those ports are present.
.. literalinclude:: ../../generators/chipyard/src/main/scala/HarnessBinders.scala
.. literalinclude:: ../../generators/chipyard/src/main/scala/harness/HarnessBinders.scala
:language: scala
:start-after: DOC include start: WithUARTAdapter
:end-before: DOC include end: WithUARTAdapter

View File

@@ -79,5 +79,4 @@ We can use this config fragment when composing our configs.
Chipyard Config Fragments
-------------------------
For discoverability, users can run ``make find-config-fragments`` to see a list of config. fragments
(config. fragments that match "class NAME extends CONFIG\n" on a single line and a subset of their children) and their file path in a fully initialized Chipyard repository.
For discoverability, users can run ``make find-config-fragments`` to see a list of config. fragments.

View File

@@ -2,16 +2,16 @@ Test Chip IP
============
Chipyard includes a Test Chip IP library which provides various hardware
widgets that may be useful when designing SoCs. This includes a :ref:`Generators/TestChipIP:Serial Adapter`,
widgets that may be useful when designing SoCs. This includes a :ref:`Generators/TestChipIP:SimTSI`,
:ref:`Generators/TestChipIP:Block Device Controller`, :ref:`Generators/TestChipIP:TileLink SERDES`, :ref:`Generators/TestChipIP:TileLink Switcher`,
:ref:`Generators/TestChipIP:TileLink Ring Network`, and :ref:`Generators/TestChipIP:UART Adapter`.
Serial Adapter
SimTSI
--------------
The serial adapter is used by tethered test chips to communicate with the host
The SimTSI and TSIToTileLink are used by tethered test chips to communicate with the host
processor. An instance of RISC-V frontend server running on the host CPU
can send commands to the serial adapter to read and write data from the memory
can send commands to the TSIToTileLink to read and write data from the memory
system. The frontend server uses this functionality to load the test program
into memory and to poll for completion of the program. More information on
this can be found in :ref:`Customization/Boot-Process:Chipyard Boot Process`.

View File

@@ -1,18 +1,11 @@
General Setup and Usage
==============================
Sources and Submodule Setup
Sources
---------------------------
All FPGA prototyping-related collateral and sources are located in the ``fpga`` top-level Chipyard directory.
This includes the ``fpga-shells`` submodule and the ``src`` directory that hold both Scala, TCL and other collateral.
However, the ``fpga-shells`` submodule repository is not initialized by default.
To initialize the ``fpga-shells`` submodule repository, run the included initialization script from the Chipyard top-level directory:
.. code-block:: shell
# in the chipyard top level folder
./scripts/init-fpga.sh
Generating a Bitstream
----------------------

View File

@@ -47,8 +47,14 @@ After the harness is created, the ``BundleBridgeSource``'s must be connected to
This is done with harness binders and io binders (see ``fpga/src/main/scala/vcu118/HarnessBinders.scala`` and ``fpga/src/main/scala/vcu118/IOBinders.scala``).
For more information on harness binders and io binders, refer to :ref:`Customization/IOBinders:IOBinders and HarnessBinders`.
Introduction to the Bringup Design
----------------------------------
(Legacy) Introduction to the Legacy Bringup Design
--------------------------------------------------
.. warning::
The bringup VCU118 design described here is designed for old versions of Chipyard SoCs, pre-1.9.1.
The key difference is that these designs rely on a clock generated on-chip to synchronize the slow serialized-TileLink interface.
After Chipyard 1.9.1, the FPGA host is expected to pass the clock to the chip, instead of the other way around.
A new bringup solution will be developed for post-1.9.1 Chipyard designs.
An example of a more complicated design used for Chipyard test chips can be viewed in ``fpga/src/main/scala/vcu118/bringup/``.
This example extends the default test harness and creates new ``Overlays`` to connect to a DUT (connected to the FMC port).

View File

@@ -151,25 +151,17 @@ Fast Memory Loading
-------------------
The simulator loads the program binary over a simulated serial line. This can be quite slow if there is a lot of static data, so the simulator also allows data to be loaded from a file directly into the DRAM model.
Loadmem files should be ELF files. In the most common use case, this can be the binary.
.. code-block:: shell
make run-binary BINARY=test.riscv LOADMEM=testdata.hex LOADMEM_ADDR=81000000
make run-binary BINARY=test.riscv LOADMEM=test.riscv
The ``.hex`` file should be a text file with a hexadecimal number on each line.
.. code-block:: text
deadbeef
0123
Each line uses little-endian order, so this file would produce the bytes "ef be ad de 01 23". ``LOADMEM_ADDR`` specifies which address in memory (in hexadecimal) to write the first byte to. The default is 0x81000000.
A special target that facilitates automatically generating a hex file for an entire elf RISC-V exectuable and then running the simulator with the appropriate flags is also available.
Usually the ``LOADMEM`` ELF is the same as the ``BINARY`` ELF, so ``LOADMEM=1`` can be used as a shortcut.
.. code-block:: shell
make run-binary-hex BINARY=test.riscv
make run-binary BINARY=test.riscv LOADMEM=1
Generating Waveforms
-----------------------

View File

@@ -32,4 +32,21 @@ In this configuration, Spike is cache-coherent, and communicates with the uncore
make CONFIG=SpikeConfig run-binary BINARY=hello.riscv
Spike-as-a-Tile also supports Tightly-Coupled-Memory (TCM) for the SpikeTile, in which the main system memory is entirely modeled
within the Spike tile, allowing for very fast simulatoin performance.
.. code-block:: shell
make CONFIG=SpikeUltraFastConfig run-binary BINARY=hello.riscv
Spike-as-a-Tile can be configured with custom IPC, commit logging, and other behaviors. Spike-specific flags can be added as plusargs to ``EXTRA_SIM_FLAGS``
.. code-block:: shell
make CONFIG=SpikeUltraFastConfig run-binary BINARY=hello.riscv EXTRA_SPIKE_FLAGS="+spike-ipc=10000 +spike-fast-clint +spike-debug" LOADMEM=1
* ``+spike-ipc=``: Sets the maximum number of instructions Spike can retire in a single "tick", or cycle of the uncore simulation.
* ``+spike-fast-clint``: Enables fast-forwarding through WFI stalls by generating fake timer interrupts
* ``+spike-debug``: Enables debug Spike logging
* ``+spike-verbose``: Enables Spike commit-log generation

View File

@@ -115,7 +115,7 @@ Timing reports are found in ``build/par-rundir/timingReports``. They are gzipped
.. code-block:: shell
./view_gds.py build/chipyard.TestHarness.TinyRocketConfig/par-rundir/ChipTop.gds
./view_gds.py build/chipyard.harness.TestHarness.TinyRocketConfig/par-rundir/ChipTop.gds
By default, this script only shows the M2 thru M4 routing. Layers can be toggled in the layout viewer's side pane and ``view_gds.py`` has a mapping of layer numbers to layer names.
@@ -126,9 +126,9 @@ To run DRC & LVS, and view the results in Calibre:
.. code-block:: shell
make drc CONFIG=TinyRocketConfig
./build/chipyard.TestHarness.TinyRocketConfig-ChipTop/drc-rundir/generated-scripts/view-drc
./build/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop/drc-rundir/generated-scripts/view-drc
make lvs CONFIG=TinyRocketConfig
./build/chipyard.TestHarness.TinyRocketConfig-ChipTop/lvs-rundir/generated-scripts/view-lvs
./build/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop/lvs-rundir/generated-scripts/view-lvs
Some DRC errors are expected from this PDK, as explained in the `ASAP7 plugin readme <https://github.com/ucb-bar/hammer/blob/master/hammer/technology/asap7>`__.
Furthermore, the dummy SRAMs that are provided in this tutorial and PDK do not have any geometry inside, so will certainly cause DRC errors.

View File

@@ -121,7 +121,7 @@ It is recommended that you edit these variables directly in the Makefile rather
The ``buildfile`` make target has dependencies on both (1) the Verilog that is elaborated from all Chisel sources
and (2) the mapping of memory instances in the design to SRAM macros;
all files related to these two steps reside in the ``generated-src/chipyard.TestHarness.TinyRocketConfig-ChipTop`` directory.
all files related to these two steps reside in the ``generated-src/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop`` directory.
Note that the files in ``generated-src`` vary for each tool/technology flow.
This especially applies to the Sky130 Commercial vs OpenROAD tutorial flows
(due to the ``ENABLE_YOSYS_FLOW`` flag present for the OpenROAD flow), so these flows should be run in separate
@@ -168,9 +168,9 @@ To run DRC & LVS, and view the results in Calibre:
.. code-block:: shell
make drc tutorial=sky130-commercial
./build/chipyard.TestHarness.TinyRocketConfig-ChipTop/drc-rundir/generated-scripts/view_drc
./build/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop/drc-rundir/generated-scripts/view_drc
make lvs tutorial=sky130-commercial
./build/chipyard.TestHarness.TinyRocketConfig-ChipTop/lvs-rundir/generated-scripts/view_lvs
./build/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop/lvs-rundir/generated-scripts/view_lvs
Some DRC errors are expected from this PDK, especially with regards to the SRAMs, as explained in the
`Sky130 Hammer plugin README <https://github.com/ucb-bar/hammer/blob/master/hammer/technology/sky130>`__.

View File

@@ -149,7 +149,7 @@ It is recommended that you edit these variables directly in the Makefile rather
The ``buildfile`` make target has dependencies on both (1) the Verilog that is elaborated from all Chisel sources
and (2) the mapping of memory instances in the design to SRAM macros;
all files related to these two steps reside in the ``generated-src/chipyard.TestHarness.TinyRocketConfig-ChipTop`` directory.
all files related to these two steps reside in the ``generated-src/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop`` directory.
Note that the files in ``generated-src`` vary for each tool/technology flow.
This especially applies to the Sky130 Commercial vs OpenROAD tutorial flows
(due to the ``ENABLE_YOSYS_FLOW`` flag, explained below), so these flows should be run in separate
@@ -197,7 +197,7 @@ Hammer generates a convenient script to launch these sessions
.. code-block:: shell
cd ./build/chipyard.TestHarness.TinyRocketConfig-ChipTop/par-rundir
cd ./build/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop/par-rundir
./generated-scripts/open_chip
Note that the conda OpenROAD package was compiled with the GUI disabled, so in order to view the layout,
@@ -212,7 +212,7 @@ These databases can be restored using the same ``open_chip`` script for debuggin
.. code-block:: shell
cd build/chipyard.TestHarness.TinyRocketConfig-ChipTop/par-rundir
cd build/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop/par-rundir
./generated_scripts/open_chip -h
"
Usage: ./generated-scripts/open_chip [-t] [openroad_db_name]
@@ -245,9 +245,9 @@ To run DRC & LVS in Magic & Netgen, respectively:
.. code-block:: shell
make drc tutorial=sky130-openroad
./build/chipyard.TestHarness.TinyRocketConfig-ChipTop/drc-rundir/generated-scripts/view_drc
./build/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop/drc-rundir/generated-scripts/view_drc
make lvs tutorial=sky130-openroad
./build/chipyard.TestHarness.TinyRocketConfig-ChipTop/lvs-rundir/generated-scripts/view_lvs
./build/chipyard.harness.TestHarness.TinyRocketConfig-ChipTop/lvs-rundir/generated-scripts/view_lvs
Note that in ``sky130-openroad.yml`` we have set the following YAML keys:

View File

@@ -1,7 +1,7 @@
// See LICENSE for license details.
package chipyard.fpga.arty
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.devices.debug._
import freechips.rocketchip.devices.tilelink._
@@ -17,11 +17,11 @@ import chipyard.{BuildSystem}
// DOC include start: AbstractArty and Rocket
class WithArtyTweaks extends Config(
new WithArtyResetHarnessBinder ++
new WithArtyJTAGHarnessBinder ++
new WithArtyUARTHarnessBinder ++
new WithArtyResetHarnessBinder ++
new WithDebugResetPassthrough ++
new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++
new chipyard.config.WithDTSTimebase(32768) ++
new testchipip.WithNoSerialTL
)

View File

@@ -2,7 +2,7 @@ package chipyard.fpga.arty
import chisel3._
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
import freechips.rocketchip.devices.debug.{HasPeripheryDebug}
import freechips.rocketchip.jtag.{JTAGIO}
import sifive.blocks.devices.uart.{UARTPortIO, HasPeripheryUARTModuleImp}
@@ -15,15 +15,15 @@ import chipyard.harness.{ComposeHarnessBinder, OverrideHarnessBinder}
import chipyard.iobinders.JTAGChipIO
class WithArtyResetHarnessBinder extends ComposeHarnessBinder({
(system: HasPeripheryDebugModuleImp, th: ArtyFPGATestHarness, ports: Seq[Bool]) => {
require(ports.size == 2)
(system: HasPeripheryDebug, th: ArtyFPGATestHarness, ports: Seq[Data]) => {
val resetPorts = ports.collect { case b: Bool => b }
require(resetPorts.size == 2)
withClockAndReset(th.clock_32MHz, th.ck_rst) {
// Debug module reset
th.dut_ndreset := ports(0)
th.dut_ndreset := resetPorts(0)
// JTAG reset
ports(1) := PowerOnResetFPGAOnly(th.clock_32MHz)
resetPorts(1) := PowerOnResetFPGAOnly(th.clock_32MHz)
}
}
})
@@ -63,6 +63,7 @@ class WithArtyJTAGHarnessBinder extends OverrideHarnessBinder({
io_jtag.TMS.i.po.map(_ := DontCare)
io_jtag.TDO.i.po.map(_ := DontCare)
}
case b: Bool =>
}
}
})

View File

@@ -3,12 +3,12 @@ package chipyard.fpga.arty
import chisel3._
import chisel3.experimental.{IO}
import freechips.rocketchip.devices.debug.{HasPeripheryDebugModuleImp}
import freechips.rocketchip.devices.debug.{HasPeripheryDebug}
import chipyard.iobinders.{ComposeIOBinder}
class WithDebugResetPassthrough extends ComposeIOBinder({
(system: HasPeripheryDebugModuleImp) => {
(system: HasPeripheryDebug) => {
// Debug module reset
val io_ndreset: Bool = IO(Output(Bool())).suggestName("ndreset")
io_ndreset := system.debug.get.ndreset

View File

@@ -3,12 +3,12 @@ package chipyard.fpga.arty
import chisel3._
import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.config.{Parameters}
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters}
import org.chipsalliance.cde.config.{Parameters}
import sifive.fpgashells.shell.xilinx.artyshell.{ArtyShell}
import chipyard.{BuildTop, HasHarnessSignalReferences}
import chipyard.harness.{ApplyHarnessBinders}
import chipyard.harness.{ApplyHarnessBinders, BuildTop, HasHarnessSignalReferences}
import chipyard.iobinders.{HasIOBinders}
class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell with HasHarnessSignalReferences {
@@ -37,4 +37,9 @@ class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell
lazyDut match { case d: HasIOBinders =>
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
}
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
implicitHarnessClockBundle.clock := buildtopClock
implicitHarnessClockBundle.reset := buildtopReset
harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle)
}

View File

@@ -1,7 +1,7 @@
// See LICENSE for license details.
package chipyard.fpga.arty100t
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.devices.debug._
import freechips.rocketchip.devices.tilelink._
@@ -22,6 +22,7 @@ class WithNoDesignKey extends Config((site, here, up) => {
})
class WithArty100TTweaks extends Config(
new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++
new WithArty100TUARTTSI ++
new WithArty100TDDRTL ++
new WithNoDesignKey ++

View File

@@ -3,8 +3,9 @@ package chipyard.fpga.arty100t
import chisel3._
import chisel3.util._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.config.{Parameters}
import org.chipsalliance.cde.config.{Parameters}
import freechips.rocketchip.tilelink.{TLClientNode, TLBlockDuringReset}
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters}
import sifive.fpgashells.shell.xilinx._
import sifive.fpgashells.shell._
@@ -13,8 +14,8 @@ import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly}
import sifive.blocks.devices.uart._
import chipyard._
import chipyard.harness.{ApplyHarnessBinders}
import chipyard.{ChipTop, CanHaveMasterTLMemPort, ExtTLMem}
import chipyard.harness._
import chipyard.iobinders.{HasIOBinders}
class Arty100THarness(override implicit val p: Parameters) extends Arty100TShell with HasHarnessSignalReferences
@@ -87,6 +88,11 @@ class Arty100THarness(override implicit val p: Parameters) extends Arty100TShell
chiptop match { case d: HasIOBinders =>
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
}
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
implicitHarnessClockBundle.clock := buildtopClock
implicitHarnessClockBundle.reset := buildtopReset
harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle)
}
}

View File

@@ -2,7 +2,6 @@ package chipyard.fpga.arty100t
import chisel3._
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
import freechips.rocketchip.jtag.{JTAGIO}
import freechips.rocketchip.subsystem.{PeripheryBusKey}
import freechips.rocketchip.tilelink.{TLBundle}
@@ -26,24 +25,25 @@ class WithArty100TUARTTSI(uartBaudRate: BigInt = 115200) extends OverrideHarness
ports.map({ port =>
val ath = th.asInstanceOf[Arty100THarness]
val freq = p(PeripheryBusKey).dtsFrequency.get
val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
val bits = port.bits
port.clock := th.buildtopClock
withClockAndReset(th.buildtopClock, th.buildtopReset) {
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset)
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset)
val uart_to_serial = Module(new UARTToSerial(
freq, UARTParams(0, initBaudRate=uartBaudRate)))
val serial_width_adapter = Module(new SerialWidthAdapter(
narrowW = 8, wideW = SerialAdapter.SERIAL_TSI_WIDTH))
narrowW = 8, wideW = TSI.WIDTH))
serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial)
ram.module.io.tsi_ser.flipConnect(serial_width_adapter.io.wide)
ram.module.io.tsi.flipConnect(serial_width_adapter.io.wide)
ath.io_uart_bb.bundle <> uart_to_serial.io.uart
ath.other_leds(1) := uart_to_serial.io.dropped
ath.other_leds(9) := ram.module.io.adapter_state(0)
ath.other_leds(10) := ram.module.io.adapter_state(1)
ath.other_leds(11) := ram.module.io.adapter_state(2)
ath.other_leds(12) := ram.module.io.adapter_state(3)
ath.other_leds(9) := ram.module.io.tsi2tl_state(0)
ath.other_leds(10) := ram.module.io.tsi2tl_state(1)
ath.other_leds(11) := ram.module.io.tsi2tl_state(2)
ath.other_leds(12) := ram.module.io.tsi2tl_state(3)
}
})
}

View File

@@ -2,7 +2,7 @@ package chipyard.fpga.vc707
import sys.process._
import freechips.rocketchip.config.{Config, Parameters}
import org.chipsalliance.cde.config.{Config, Parameters}
import freechips.rocketchip.subsystem.{SystemBusKey, PeripheryBusKey, ControlBusKey, ExtMem}
import freechips.rocketchip.devices.debug.{DebugModuleKey, ExportDebug, JTAG}
import freechips.rocketchip.devices.tilelink.{DevNullParams, BootROMLocated}
@@ -17,7 +17,8 @@ import sifive.fpgashells.shell.xilinx.{VC7074GDDRSize}
import testchipip.{SerialTLKey}
import chipyard.{BuildSystem, ExtTLMem, DefaultClockFrequencyKey}
import chipyard.{BuildSystem, ExtTLMem}
import chipyard.harness.{DefaultClockFrequencyKey}
class WithDefaultPeripherals extends Config((site, here, up) => {
case PeripheryUARTKey => List(UARTParams(address = BigInt(0x64000000L)))
@@ -39,6 +40,7 @@ class WithSystemModifications extends Config((site, here, up) => {
class WithVC707Tweaks extends Config (
// harness binders
new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++
new WithVC707UARTHarnessBinder ++
new WithVC707SPISDCardHarnessBinder ++
new WithVC707DDRMemHarnessBinder ++

View File

@@ -4,8 +4,9 @@ import chisel3._
import chisel3.experimental.{IO}
import freechips.rocketchip.diplomacy.{LazyModule, LazyRawModuleImp, BundleBridgeSource}
import freechips.rocketchip.config.{Parameters}
import org.chipsalliance.cde.config.{Parameters}
import freechips.rocketchip.tilelink.{TLClientNode}
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters}
import sifive.fpgashells.shell.xilinx.{VC707Shell, UARTVC707ShellPlacer, PCIeVC707ShellPlacer, ChipLinkVC707PlacedOverlay}
import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly}
@@ -16,9 +17,9 @@ import sifive.fpgashells.devices.xilinx.xilinxvc707pciex1.{XilinxVC707PCIeX1IO}
import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTPortIO}
import sifive.blocks.devices.spi.{PeripherySPIKey, SPIPortIO}
import chipyard.{HasHarnessSignalReferences, BuildTop, ChipTop, ExtTLMem, CanHaveMasterTLMemPort, DefaultClockFrequencyKey}
import chipyard.{ChipTop, ExtTLMem, CanHaveMasterTLMemPort}
import chipyard.iobinders.{HasIOBinders}
import chipyard.harness.{ApplyHarnessBinders}
import chipyard.harness.{ApplyHarnessBinders, HasHarnessSignalReferences, BuildTop, DefaultClockFrequencyKey}
class VC707FPGATestHarness(override implicit val p: Parameters) extends VC707Shell { outer =>
@@ -132,4 +133,9 @@ class VC707FPGATestHarnessImp(_outer: VC707FPGATestHarness) extends LazyRawModul
// check the top-level reference clock is equal to the default
// non-exhaustive since you need all ChipTop clocks to equal the default
require(getRefClockFreq == p(DefaultClockFrequencyKey))
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
implicitHarnessClockBundle.clock := buildtopClock
implicitHarnessClockBundle.reset := buildtopReset
harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle)
}

View File

@@ -2,7 +2,7 @@ package chipyard.fpga.vcu118
import sys.process._
import freechips.rocketchip.config.{Config, Parameters}
import org.chipsalliance.cde.config.{Config, Parameters}
import freechips.rocketchip.subsystem.{SystemBusKey, PeripheryBusKey, ControlBusKey, ExtMem}
import freechips.rocketchip.devices.debug.{DebugModuleKey, ExportDebug, JTAG}
import freechips.rocketchip.devices.tilelink.{DevNullParams, BootROMLocated}
@@ -17,7 +17,8 @@ import sifive.fpgashells.shell.xilinx.{VCU118ShellPMOD, VCU118DDRSize}
import testchipip.{SerialTLKey}
import chipyard.{BuildSystem, ExtTLMem, DefaultClockFrequencyKey}
import chipyard.{BuildSystem, ExtTLMem}
import chipyard.harness.{DefaultClockFrequencyKey}
class WithDefaultPeripherals extends Config((site, here, up) => {
case PeripheryUARTKey => List(UARTParams(address = BigInt(0x64000000L)))
@@ -41,6 +42,7 @@ class WithSystemModifications extends Config((site, here, up) => {
// DOC include start: AbstractVCU118 and Rocket
class WithVCU118Tweaks extends Config(
// harness binders
new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++
new WithUART ++
new WithSPISDCard ++
new WithDDRMem ++

View File

@@ -3,7 +3,7 @@ package chipyard.fpga.vcu118
import chisel3._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.config.{Parameters, Field}
import org.chipsalliance.cde.config.{Parameters, Field}
import freechips.rocketchip.tilelink.{TLInwardNode, TLAsyncCrossingSink}
import sifive.fpgashells.shell._

View File

@@ -9,8 +9,8 @@ import freechips.rocketchip.tilelink.{TLBundle}
import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp, UARTPortIO}
import sifive.blocks.devices.spi.{HasPeripherySPI, SPIPortIO}
import chipyard.{HasHarnessSignalReferences, CanHaveMasterTLMemPort}
import chipyard.harness.{OverrideHarnessBinder}
import chipyard.{CanHaveMasterTLMemPort}
import chipyard.harness.{HasHarnessSignalReferences, OverrideHarnessBinder}
/*** UART ***/
class WithUART extends OverrideHarnessBinder({

View File

@@ -4,8 +4,9 @@ import chisel3._
import chisel3.experimental.{IO}
import freechips.rocketchip.diplomacy.{LazyModule, LazyRawModuleImp, BundleBridgeSource}
import freechips.rocketchip.config.{Parameters}
import org.chipsalliance.cde.config.{Parameters}
import freechips.rocketchip.tilelink.{TLClientNode}
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters}
import sifive.fpgashells.shell.xilinx._
import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly}
@@ -17,7 +18,7 @@ import sifive.blocks.devices.spi.{PeripherySPIKey, SPIPortIO}
import chipyard._
import chipyard.iobinders.{HasIOBinders}
import chipyard.harness.{ApplyHarnessBinders}
import chipyard.harness._
class VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118ShellBasicOverlays {
@@ -134,4 +135,9 @@ class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawMod
// check the top-level reference clock is equal to the default
// non-exhaustive since you need all ChipTop clocks to equal the default
require(getRefClockFreq == p(DefaultClockFrequencyKey))
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
implicitHarnessClockBundle.clock := buildtopClock
implicitHarnessClockBundle.reset := buildtopReset
harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle)
}

View File

@@ -2,7 +2,7 @@ package chipyard.fpga.vcu118.bringup
import math.min
import freechips.rocketchip.config.{Config, Parameters}
import org.chipsalliance.cde.config.{Config, Parameters}
import freechips.rocketchip.diplomacy.{DTSModel, DTSTimebase, RegionType, AddressSet, ResourceBinding, Resource, ResourceAddress}
import freechips.rocketchip.tilelink._
import freechips.rocketchip.diplomacy._

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.experimental.{attach}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.config.{Parameters, Field}
import org.chipsalliance.cde.config.{Parameters, Field}
import freechips.rocketchip.tilelink.{TLInwardNode, TLAsyncCrossingSink}
import sifive.fpgashells.shell._

View File

@@ -4,7 +4,7 @@ import chisel3._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.system._
import freechips.rocketchip.config.Parameters
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._

View File

@@ -13,8 +13,7 @@ import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp, GPIOPortIO}
import testchipip.{HasPeripheryTSIHostWidget, TSIHostWidgetIO}
import chipyard.{HasHarnessSignalReferences}
import chipyard.harness.{ComposeHarnessBinder, OverrideHarnessBinder}
import chipyard.harness.{ComposeHarnessBinder, OverrideHarnessBinder, HasHarnessSignalReferences}
/*** UART ***/
class WithBringupUART extends ComposeHarnessBinder({

View File

@@ -3,7 +3,7 @@ package chipyard.fpga.vcu118.bringup
import chisel3._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tilelink._

View File

@@ -1,3 +1,4 @@
#include <cstdint>
#include <vector>
#include <string>
#include <riscv/sim.h>
@@ -5,6 +6,25 @@
#include <svdpi.h>
#include <sstream>
#include <set>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <fcntl.h>
#if __has_include ("cospike_dtm.h")
#define COSPIKE_DTM
#include "testchip_dtm.h"
extern testchip_dtm_t* dtm;
bool spike_loadarch_done = false;
#endif
#if __has_include ("mm.h")
#define COSPIKE_SIMDRAM
#include "mm.h"
extern std::map<long long int, backing_data_t> backing_mem_data;
#endif
#define CLINT_BASE (0x2000000)
#define CLINT_SIZE (0x1000)
@@ -20,6 +40,7 @@ typedef struct system_info_t {
system_info_t* info = NULL;
sim_t* sim = NULL;
bool cospike_debug;
reg_t tohost_addr = 0;
reg_t fromhost_addr = 0;
std::set<reg_t> magic_addrs;
@@ -42,7 +63,8 @@ extern "C" void cospike_set_sysinfo(char* isa, int pmpregions,
) {
if (!info) {
info = new system_info_t;
info->isa = std::string(isa);
// technically the targets aren't zicntr compliant, but they implement the zicntr registers
info->isa = std::string(isa) + "_zicntr";
info->pmpregions = pmpregions;
info->mem0_base = mem0_base;
info->mem0_size = mem0_size;
@@ -64,10 +86,11 @@ extern "C" void cospike_cosim(long long int cycle,
int raise_exception,
int raise_interrupt,
unsigned long long int cause,
unsigned long long int wdata)
unsigned long long int wdata,
int priv)
{
assert(info);
if (!sim) {
if (unlikely(!sim)) {
printf("Configuring spike cosim\n");
std::vector<mem_cfg_t> mem_cfg;
std::vector<size_t> hartids;
@@ -110,7 +133,7 @@ extern "C" void cospike_cosim(long long int cycle,
abort();
std::vector<std::string> htif_args;
bool in_permissive = false;
bool cospike_debug = false;
cospike_debug = false;
for (int i = 1; i < vinfo.argc; i++) {
std::string arg(vinfo.argv[i]);
if (arg == "+permissive") {
@@ -136,7 +159,7 @@ extern "C" void cospike_cosim(long long int cycle,
.support_impebreak = true
};
printf("%s\n", info->isa.c_str());
printf("isa string is %s\n", info->isa.c_str());
for (int i = 0; i < htif_args.size(); i++) {
printf("%s\n", htif_args[i].c_str());
}
@@ -146,13 +169,29 @@ extern "C" void cospike_cosim(long long int cycle,
plugin_devices,
htif_args,
dm_config,
nullptr,
"cospike.log",
false,
nullptr,
false,
nullptr
);
#ifdef COSPIKE_SIMDRAM
// match sim_t's backing memory with the SimDRAM memory
bus_t temp_mem_bus;
for (auto& pair : mems) temp_mem_bus.add_device(pair.first, pair.second);
for (auto& pair : backing_mem_data) {
size_t base = pair.first;
size_t size = pair.second.size;
printf("Matching spike memory initial state for region %lx-%lx\n", base, base + size);
if (!temp_mem_bus.store(base, size, pair.second.data)) {
printf("Error, unable to match memory at address %lx\n", base);
abort();
}
}
#endif
sim->configure_log(true, true);
// Use our own reset vector
for (int i = 0; i < info->nharts; i++) {
@@ -166,93 +205,207 @@ extern "C" void cospike_cosim(long long int cycle,
fromhost_addr = ((htif_t*)sim)->get_fromhost_addr();
printf("Tohost : %lx\n", tohost_addr);
printf("Fromhost: %lx\n", fromhost_addr);
printf("Memory base : %lx\n", info->mem0_base);
printf("Memory Size : %lx\n", info->mem0_size);
}
if (priv & 0x4) { // debug
return;
}
processor_t* p = sim->get_core(hartid);
state_t* s = p->get_state();
#ifdef COSPIKE_DTM
if (dtm && dtm->loadarch_done && !spike_loadarch_done) {
printf("Restoring spike state from testchip_dtm loadarch\n");
// copy the loadarch state into the cosim
loadarch_state_t &ls = dtm->loadarch_state[hartid];
s->pc = ls.pc;
s->prv = ls.prv;
s->csrmap[CSR_MSTATUS]->write(s->csrmap[CSR_MSTATUS]->read() | MSTATUS_VS | MSTATUS_XS | MSTATUS_FS);
#define RESTORE(CSRID, csr) s->csrmap[CSRID]->write(ls.csr);
RESTORE(CSR_FCSR , fcsr);
RESTORE(CSR_VSTART , vstart);
RESTORE(CSR_VXSAT , vxsat);
RESTORE(CSR_VXRM , vxrm);
RESTORE(CSR_VCSR , vcsr);
RESTORE(CSR_VTYPE , vtype);
RESTORE(CSR_STVEC , stvec);
RESTORE(CSR_SSCRATCH , sscratch);
RESTORE(CSR_SEPC , sepc);
RESTORE(CSR_SCAUSE , scause);
RESTORE(CSR_STVAL , stval);
RESTORE(CSR_SATP , satp);
RESTORE(CSR_MSTATUS , mstatus);
RESTORE(CSR_MEDELEG , medeleg);
RESTORE(CSR_MIDELEG , mideleg);
RESTORE(CSR_MIE , mie);
RESTORE(CSR_MTVEC , mtvec);
RESTORE(CSR_MSCRATCH , mscratch);
RESTORE(CSR_MEPC , mepc);
RESTORE(CSR_MCAUSE , mcause);
RESTORE(CSR_MTVAL , mtval);
RESTORE(CSR_MIP , mip);
RESTORE(CSR_MCYCLE , mcycle);
RESTORE(CSR_MINSTRET , minstret);
if (ls.VLEN != p->VU.VLEN) {
printf("VLEN mismatch loadarch: $d != spike: $d\n", ls.VLEN, p->VU.VLEN);
abort();
}
if (ls.ELEN != p->VU.ELEN) {
printf("ELEN mismatch loadarch: $d != spike: $d\n", ls.ELEN, p->VU.ELEN);
abort();
}
for (size_t i = 0; i < 32; i++) {
s->XPR.write(i, ls.XPR[i]);
s->FPR.write(i, { (uint64_t)ls.FPR[i], (uint64_t)-1 });
memcpy(p->VU.reg_file + i * ls.VLEN / 8, ls.VPR[i], ls.VLEN / 8);
}
spike_loadarch_done = true;
p->clear_waiting_for_interrupt();
}
#endif
uint64_t s_pc = s->pc;
uint64_t interrupt_cause = cause & 0x7FFFFFFFFFFFFFFF;
bool ssip_interrupt = interrupt_cause == 0x1;
bool msip_interrupt = interrupt_cause == 0x3;
bool debug_interrupt = interrupt_cause == 0xe;
if (raise_interrupt) {
printf("%d interrupt %lx\n", cycle, cause);
uint64_t interrupt_cause = cause & 0x7FFFFFFFFFFFFFFF;
if (interrupt_cause == 3) {
if (ssip_interrupt) {
// do nothing
} else if (msip_interrupt) {
s->mip->backdoor_write_with_mask(MIP_MSIP, MIP_MSIP);
} else if (debug_interrupt) {
return;
} else {
printf("Unknown interrupt %lx\n", interrupt_cause);
abort();
}
}
if (raise_exception)
printf("%d exception %lx\n", cycle, cause);
if (valid) {
printf("%d Cosim: %lx", cycle, iaddr);
if (has_wdata) {
printf(" %lx", wdata);
}
// if (has_wdata) {
// printf(" s: %lx", wdata);
// }
printf("\n");
}
if (valid || raise_interrupt || raise_exception)
if (valid || raise_interrupt || raise_exception) {
p->step(1);
if (unlikely(cospike_debug)) {
printf("spike pc is %lx\n", s->pc);
printf("spike mstatus is %lx\n", s->mstatus->read());
printf("spike mip is %lx\n", s->mip->read());
printf("spike mie is %lx\n", s->mie->read());
}
}
if (valid) {
if (valid && !raise_exception) {
if (s_pc != iaddr) {
printf("%d PC mismatch %lx != %lx\n", cycle, s_pc, iaddr);
printf("%d PC mismatch spike %llx != DUT %llx\n", cycle, s_pc, iaddr);
if (unlikely(cospike_debug)) {
printf("spike mstatus is %lx\n", s->mstatus->read());
printf("spike mcause is %lx\n", s->mcause->read());
printf("spike mtval is %lx\n" , s->mtval->read());
printf("spike mtinst is %lx\n", s->mtinst->read());
}
exit(1);
}
// Try to remember magic_mem addrs, and ignore these in the future
auto& mem_write = s->log_mem_write;
if (!mem_write.empty() && tohost_addr && std::get<0>(mem_write[0]) == tohost_addr) {
reg_t wdata = std::get<1>(mem_write[0]);
if (wdata >= info->mem0_base && wdata < (info->mem0_base + info->mem0_size)) {
printf("Probable magic mem %x\n", wdata);
magic_addrs.insert(wdata);
auto& log = s->log_reg_write;
auto& mem_read = s->log_mem_read;
for (auto memwrite : mem_write) {
reg_t waddr = std::get<0>(memwrite);
uint64_t w_data = std::get<1>(memwrite);
if ((waddr == CLINT_BASE + 4*hartid) && w_data == 0) {
s->mip->backdoor_write_with_mask(MIP_MSIP, 0);
}
// Try to remember magic_mem addrs, and ignore these in the future
if ( waddr == tohost_addr && w_data >= info->mem0_base && w_data < (info->mem0_base + info->mem0_size)) {
printf("Probable magic mem %lx\n", w_data);
magic_addrs.insert(w_data);
}
// Try to remember magic_mem addrs, and ignore these in the future
if ( waddr == tohost_addr && w_data >= info->mem0_base && w_data < (info->mem0_base + info->mem0_size)) {
printf("Probable magic mem %lx\n", w_data);
magic_addrs.insert(w_data);
}
}
if (has_wdata) {
auto& log = s->log_reg_write;
auto& mem_read = s->log_mem_read;
bool scalar_wb = false;
bool vector_wb = false;
uint32_t vector_cnt = 0;
for (auto &regwrite : log) {
//TODO: scaling to multi issue reads?
reg_t mem_read_addr = mem_read.empty() ? 0 : std::get<0>(mem_read[0]);
for (auto regwrite : log) {
int rd = regwrite.first >> 4;
int type = regwrite.first & 0xf;
// 0 => int
// 1 => fp
// 2 => vec
// 3 => vec hint
// 4 => csr
if ((rd != 0 && type == 0) || type == 1) {
// Override reads from some CSRs
uint64_t csr_addr = (insn >> 20) & 0xfff;
bool csr_read = (insn & 0x7f) == 0x73;
if (csr_read) printf("CSR read %lx\n", csr_addr);
if (csr_read && (
(csr_addr == 0x301) || // misa
(csr_addr == 0xf13) || // mimpid
(csr_addr == 0xf12) || // marchid
(csr_addr == 0xf11) || // mvendorid
(csr_addr == 0xb00) || // mcycle
(csr_addr == 0xb02) || // minstret
(csr_addr >= 0x3b0 && csr_addr <= 0x3ef) // pmpaddr
)) {
printf("CSR override\n");
s->XPR.write(rd, wdata);
} else if (!mem_read.empty() && ((magic_addrs.count(mem_read_addr) ||
(tohost_addr && mem_read_addr == tohost_addr) ||
(fromhost_addr && mem_read_addr == fromhost_addr) ||
(CLINT_BASE <= mem_read_addr && mem_read_addr < (CLINT_BASE + CLINT_SIZE))
))) {
// Don't check reads from tohost, reads from magic memory, or reads from clint
// Technically this could be buggy because log_mem_read only reports vaddrs, but
// no software ever should access tohost/fromhost/clint with vaddrs anyways
printf("Read override %lx\n", mem_read_addr);
s->XPR.write(rd, wdata);
} else if (wdata != regwrite.second.v[0]) {
printf("%d wdata mismatch reg %d %lx != %lx\n", cycle, rd, regwrite.second.v[0], wdata);
exit(1);
}
}
int rd = regwrite.first >> 4;
int type = regwrite.first & 0xf;
// 0 => int
// 1 => fp
// 2 => vec
// 3 => vec hint
// 4 => csr
bool ignore_read = (!mem_read.empty() &&
((magic_addrs.count(mem_read_addr) ||
(tohost_addr && mem_read_addr == tohost_addr) ||
(fromhost_addr && mem_read_addr == fromhost_addr) ||
(CLINT_BASE <= mem_read_addr && mem_read_addr < (CLINT_BASE + CLINT_SIZE)))));
// check the type is compliant with writeback first
if ((type == 0 || type == 1))
scalar_wb = true;
if (type == 2) {
vector_wb = true;
}
if (type == 3) continue;
if ((rd != 0 && type == 0) || type == 1) {
// Override reads from some CSRs
uint64_t csr_addr = (insn >> 20) & 0xfff;
bool csr_read = (insn & 0x7f) == 0x73;
if (csr_read)
printf("CSR read %lx\n", csr_addr);
if (csr_read && ((csr_addr == 0xf13) || // mimpid
(csr_addr == 0xf12) || // marchid
(csr_addr == 0xf11) || // mvendorid
(csr_addr == 0xb00) || // mcycle
(csr_addr == 0xb02) || // minstret
(csr_addr >= 0x7a0 && csr_addr <= 0x7aa) || // debug trigger registers
(csr_addr >= 0x3b0 && csr_addr <= 0x3ef) // pmpaddr
)) {
printf("CSR override\n");
s->XPR.write(rd, wdata);
} else if (ignore_read) {
// Don't check reads from tohost, reads from magic memory, or reads
// from clint Technically this could be buggy because log_mem_read
// only reports vaddrs, but no software ever should access
// tohost/fromhost/clint with vaddrs anyways
printf("Read override %lx\n", mem_read_addr);
s->XPR.write(rd, wdata);
} else if (wdata != regwrite.second.v[0]) {
printf("%d wdata mismatch reg %d %lx != %lx\n", cycle, rd,
regwrite.second.v[0], wdata);
exit(1);
}
}
// TODO FIX: Rocketchip TracedInstruction.wdata should be Valid(UInt)
// if (scalar_wb ^ has_wdata) {
// printf("Scalar wdata behavior divergence between spike and DUT\n");
// exit(-1);
// }
}
}
}
// }

View File

@@ -1,394 +0,0 @@
// See LICENSE.SiFive for license details.
// See LICENSE.Berkeley for license details.
#if VM_TRACE
#include <memory>
#if CY_FST_TRACE
#include "verilated_fst_c.h"
#else
#include "verilated.h"
#include "verilated_vcd_c.h"
#endif // CY_FST_TRACE
#endif // VM_TRACE
#include <fesvr/dtm.h>
#include <fesvr/tsi.h>
#include "remote_bitbang.h"
#include <iostream>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
// For option parsing, which is split across this file, Verilog, and
// FESVR's HTIF, a few external files must be pulled in. The list of
// files and what they provide is enumerated:
//
// $RISCV/include/fesvr/htif.h:
// defines:
// - HTIF_USAGE_OPTIONS
// - HTIF_LONG_OPTIONS_OPTIND
// - HTIF_LONG_OPTIONS
// $(ROCKETCHIP_DIR)/generated-src(-debug)?/$(CONFIG).plusArgs:
// defines:
// - PLUSARG_USAGE_OPTIONS
// variables:
// - static const char * verilog_plusargs
extern tsi_t* tsi;
extern dtm_t* dtm;
extern remote_bitbang_t * jtag;
static uint64_t trace_count = 0;
bool verbose = false;
bool done_reset = false;
void handle_sigterm(int sig)
{
dtm->stop();
}
double sc_time_stamp()
{
return trace_count;
}
static void usage(const char * program_name)
{
printf("Usage: %s [EMULATOR OPTION]... [VERILOG PLUSARG]... [HOST OPTION]... BINARY [TARGET OPTION]...\n",
program_name);
fputs("\
Run a BINARY on the Rocket Chip emulator.\n\
\n\
Mandatory arguments to long options are mandatory for short options too.\n\
\n\
EMULATOR OPTIONS\n\
-c, --cycle-count Print the cycle count before exiting\n\
+cycle-count\n\
-h, --help Display this help and exit\n\
-m, --max-cycles=CYCLES Kill the emulation after CYCLES\n\
+max-cycles=CYCLES\n\
-s, --seed=SEED Use random number seed SEED\n\
-r, --rbb-port=PORT Use PORT for remote bit bang (with OpenOCD and GDB) \n\
If not specified, a random port will be chosen\n\
automatically.\n\
-V, --verbose Enable all Chisel printfs (cycle-by-cycle info)\n\
+verbose\n\
", stdout);
#if VM_TRACE == 0
fputs("\
\n\
EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n",
stdout);
#endif
fputs("\
-v, --vcd=FILE, Write vcd trace to FILE (or '-' for stdout)\n\
-x, --dump-start=CYCLE Start VCD tracing at CYCLE\n\
+dump-start\n\
", stdout);
fputs("\n" PLUSARG_USAGE_OPTIONS, stdout);
fputs("\n" HTIF_USAGE_OPTIONS, stdout);
printf("\n"
"EXAMPLES\n"
" - run a bare metal test:\n"
" %s $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n"
" - run a bare metal test showing cycle-by-cycle information:\n"
" %s +verbose $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add 2>&1 | spike-dasm\n"
#if VM_TRACE
" - run a bare metal test to generate a VCD waveform:\n"
" %s -v rv64ui-p-add.vcd $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n"
#endif
" - run an ELF (you wrote, called 'hello') using the proxy kernel:\n"
" %s pk hello\n",
program_name, program_name, program_name
#if VM_TRACE
, program_name
#endif
);
}
int main(int argc, char** argv)
{
unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid();
uint64_t max_cycles = -1;
int ret = 0;
bool print_cycles = false;
// 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
int verilog_plusargs_legal = 1;
int verilated_argc = 1;
char** verilated_argv = new char*[argc];
verilated_argv[0] = argv[0];
opterr = 1;
while (1) {
static struct option long_options[] = {
{"cycle-count", no_argument, 0, 'c' },
{"help", no_argument, 0, 'h' },
{"max-cycles", required_argument, 0, 'm' },
{"seed", required_argument, 0, 's' },
{"rbb-port", required_argument, 0, 'r' },
{"verbose", no_argument, 0, 'V' },
{"permissive", no_argument, 0, 'p' },
{"permissive-off", no_argument, 0, 'o' },
#if VM_TRACE
{"vcd", required_argument, 0, 'v' },
{"dump-start", required_argument, 0, 'x' },
#endif
HTIF_LONG_OPTIONS
};
int option_index = 0;
#if VM_TRACE
int c = getopt_long(argc, argv, "-chm:s:r:v:Vx:po", long_options, &option_index);
#else
int c = getopt_long(argc, argv, "-chm:s:r:Vpo", long_options, &option_index);
#endif
if (c == -1) break;
retry:
switch (c) {
// Process long and short EMULATOR options
case '?': usage(argv[0]); return 1;
case 'c': print_cycles = true; break;
case 'h': usage(argv[0]); return 0;
case 'm': max_cycles = atoll(optarg); break;
case 's': random_seed = atoi(optarg); break;
case 'r': rbb_port = atoi(optarg); break;
case 'V': verbose = true; break;
case 'p': opterr = 0; break;
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";
return 1;
}
break;
}
case 'x': start = atoll(optarg); break;
#endif
// Process legacy '+' EMULATOR arguments by replacing them with
// their getopt equivalents
case 1: {
std::string arg = optarg;
if (arg.substr(0, 1) != "+") {
optind--;
goto done_processing;
}
if (arg == "+verbose")
c = 'V';
else if (arg.substr(0, 12) == "+max-cycles=") {
c = 'm';
optarg = optarg+12;
}
#if VM_TRACE
else if (arg.substr(0, 12) == "+dump-start=") {
c = 'x';
optarg = optarg+12;
}
#endif
else if (arg.substr(0, 12) == "+cycle-count")
c = 'c';
else if (arg == "+permissive")
{
c = 'p';
verilated_argv[verilated_argc++] = optarg;
}
else if (arg == "+permissive-off")
{
c = 'o';
verilated_argv[verilated_argc++] = optarg;
}
// If we don't find a legacy '+' EMULATOR argument, it still could be
// a VERILOG_PLUSARG and not an error.
else if (verilog_plusargs_legal) {
const char ** plusarg = &verilog_plusargs[0];
int legal_verilog_plusarg = 0;
while (*plusarg && (legal_verilog_plusarg == 0)){
if (arg.substr(1, strlen(*plusarg)) == *plusarg) {
legal_verilog_plusarg = 1;
}
plusarg ++;
}
if (!legal_verilog_plusarg) {
verilog_plusargs_legal = 0;
} else {
c = 'P';
}
goto retry;
}
// If we STILL don't find a legacy '+' argument, it still could be
// an HTIF (HOST) argument and not an error. If this is the case, then
// we're done processing EMULATOR and VERILOG arguments.
else {
static struct option htif_long_options [] = { HTIF_LONG_OPTIONS };
struct option * htif_option = &htif_long_options[0];
while (htif_option->name) {
if (arg.substr(1, strlen(htif_option->name)) == htif_option->name) {
optind--;
goto done_processing;
}
htif_option++;
}
if(opterr) {
std::cerr << argv[0] << ": invalid plus-arg (Verilog or HTIF) \""
<< arg << "\"\n";
c = '?';
} else {
c = 'P';
}
}
goto retry;
}
case 'P': // Verilog PlusArg, add to the argument list for verilator environment
verilated_argv[verilated_argc++] = optarg;
break;
// Realize that we've hit HTIF (HOST) arguments or error out
default:
if (c >= HTIF_LONG_OPTIONS_OPTIND) {
optind--;
goto done_processing;
}
c = '?';
goto retry;
}
}
done_processing:
if (optind == argc) {
std::cerr << "No binary specified for emulator\n";
usage(argv[0]);
return 1;
}
// Copy remaining HTIF arguments (if any) and the binary file name into the verilator argument stack
while (optind < argc) verilated_argv[verilated_argc++] = argv[optind++];
if (verbose)
fprintf(stderr, "using random seed %u\n", random_seed);
srand(random_seed);
srand48(random_seed);
Verilated::randReset(2);
Verilated::commandArgs(verilated_argc, verilated_argv);
TEST_HARNESS *tile = new TEST_HARNESS;
#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()));
#endif // CY_FST_TRACE
if (vcdfile_name) {
tile->trace(tfp.get(), 99); // Trace 99 levels of hierarchy
tfp->open(vcdfile_name);
}
#endif // VM_TRACE
// RocketChip currently only supports RBB port 0, so this needs to stay here
jtag = new remote_bitbang_t(rbb_port);
signal(SIGTERM, handle_sigterm);
bool dump;
// start reset off low so a rising edge triggers async reset
tile->reset = 0;
tile->clock = 0;
tile->eval();
// reset for several cycles to handle pipelined reset
for (int i = 0; i < 100; i++) {
tile->reset = 1;
tile->clock = 0;
tile->eval();
#if VM_TRACE
dump = tfp && trace_count >= start;
if (dump)
tfp->dump(static_cast<vluint64_t>(trace_count * 2));
#endif
tile->clock = 1;
tile->eval();
#if VM_TRACE
if (dump)
tfp->dump(static_cast<vluint64_t>(trace_count * 2 + 1));
#endif
trace_count ++;
}
tile->reset = 0;
done_reset = true;
do {
tile->clock = 0;
tile->eval();
#if VM_TRACE
dump = tfp && trace_count >= start;
if (dump)
tfp->dump(static_cast<vluint64_t>(trace_count * 2));
#endif
tile->clock = 1;
tile->eval();
#if VM_TRACE
if (dump)
tfp->dump(static_cast<vluint64_t>(trace_count * 2 + 1));
#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)
tfp->close();
if (vcdfile)
fclose(vcdfile);
#endif
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 && 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 && 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();
}
else if (trace_count == max_cycles)
{
fprintf(stderr, "*** FAILED *** via trace_count (timeout, seed %d) after %ld cycles\n", random_seed, trace_count);
ret = 2;
}
else if (verbose || print_cycles)
{
fprintf(stderr, "*** PASSED *** Completed after %ld cycles\n", trace_count);
}
if (dtm) delete dtm;
if (tsi) delete tsi;
if (jtag) delete jtag;
if (tile) delete tile;
if (verilated_argv) delete[] verilated_argv;
return ret;
}

View File

@@ -2,11 +2,23 @@
#include <riscv/processor.h>
#include <riscv/log_file.h>
#include <fesvr/context.h>
#include <fesvr/htif.h>
#include <fesvr/memif.h>
#include <fesvr/elfloader.h>
#include <map>
#include <sstream>
#include <vpi_user.h>
#include <svdpi.h>
#if __has_include("spiketile_tsi.h")
#define SPIKETILE_HTIF_TSI
extern htif_t* tsi;
#endif
#if __has_include("spiketile_dtm.h")
#define SPIKETILE_HTIF_DTM
extern htif_t* dtm;
#endif
enum transfer_t {
NToB,
NToT,
@@ -73,8 +85,18 @@ public:
void dcache_b(uint64_t address, uint64_t source, int param);
bool dcache_c(uint64_t *address, uint64_t* source, int* param, unsigned char* voluntary, unsigned char* has_data, uint64_t* data[8]);
void dcache_d(uint64_t sourceid, uint64_t data[8], unsigned char has_data, unsigned char grantack);
void tcm_a(uint64_t address, uint64_t data, uint32_t mask, uint32_t opcode, uint32_t size);
bool tcm_d(uint64_t *data);
void loadmem(size_t base, const char* fname);
void drain_stq();
bool stq_empty() { return st_q.size() == 0; };
void flush_icache();
const cfg_t &get_cfg() const { return cfg; }
const std::map<size_t, processor_t*>& get_harts() const { return harts; }
~chipyard_simif_t() { };
chipyard_simif_t(size_t icache_ways,
@@ -86,9 +108,18 @@ public:
char* readonly_uncacheable,
char* executable,
size_t icache_sourceids,
size_t dcache_sourceids);
size_t dcache_sourceids,
size_t tcm_base,
size_t tcm_size,
const char* isastr,
size_t pmpregions);
uint64_t cycle;
bool use_stq;
htif_t *htif;
bool fast_clint;
cfg_t cfg;
std::map<size_t, processor_t*> harts;
bool accessed_tofrom_host;
private:
bool handle_cache_access(reg_t addr, size_t len,
uint8_t* load_bytes,
@@ -133,6 +164,11 @@ private:
uint64_t mmio_stdata;
size_t mmio_len;
uint64_t mmio_lddata;
uint64_t tcm_base;
uint64_t tcm_size;
uint8_t* tcm;
std::vector<uint64_t> tcm_q;
};
class tile_t {
@@ -163,6 +199,7 @@ extern "C" void spike_tile(int hartid, char* isa,
int dcache_sets, int dcache_ways,
char* cacheable, char* uncacheable, char* readonly_uncacheable, char* executable,
int icache_sourceids, int dcache_sourceids,
long long int tcm_base, long long int tcm_size,
long long int reset_vector,
long long int ipc,
long long int cycle,
@@ -237,7 +274,18 @@ extern "C" void spike_tile(int hartid, char* isa,
int* mmio_a_size,
unsigned char mmio_d_valid,
long long int mmio_d_data
long long int mmio_d_data,
unsigned char tcm_a_valid,
long long int tcm_a_address,
long long int tcm_a_data,
int tcm_a_mask,
int tcm_a_opcode,
int tcm_a_size,
unsigned char* tcm_d_valid,
unsigned char tcm_d_ready,
long long int* tcm_d_data
)
{
if (!host) {
@@ -248,36 +296,26 @@ extern "C" void spike_tile(int hartid, char* isa,
if (tiles.find(hartid) == tiles.end()) {
printf("Constructing spike processor_t\n");
isa_parser_t *isa_parser = new isa_parser_t(isa, "MSU");
std::string* isastr = new std::string(isa);
chipyard_simif_t* simif = new chipyard_simif_t(icache_ways, icache_sets,
dcache_ways, dcache_sets,
cacheable, uncacheable, readonly_uncacheable, executable,
icache_sourceids, dcache_sourceids);
std::string* isastr = new std::string(isa);
cfg_t* cfg = new cfg_t(std::make_pair(0, 0),
nullptr,
isastr->c_str(),
"MSU",
"vlen:128,elen:64",
false,
endianness_little,
pmpregions,
std::vector<mem_cfg_t>(),
std::vector<size_t>(),
false,
0);
icache_sourceids, dcache_sourceids,
tcm_base, tcm_size,
isastr->c_str(), pmpregions);
processor_t* p = new processor_t(isa_parser,
cfg,
&simif->get_cfg(),
simif,
hartid,
false,
log_file->get(),
sout);
p->enable_log_commits();
simif->harts[hartid] = p;
s_vpi_vlog_info vinfo;
if (!vpi_get_vlog_info(&vinfo))
abort();
std::string loadmem_file = "";
for (int i = 1; i < vinfo.argc; i++) {
std::string arg(vinfo.argv[i]);
if (arg == "+spike-debug") {
@@ -286,7 +324,18 @@ extern "C" void spike_tile(int hartid, char* isa,
if (arg == "+spike-stq") {
simif->use_stq = true;
}
if (arg.find("+loadmem=") == 0) {
loadmem_file = arg.substr(strlen("+loadmem="));
}
if (arg == "+spike-fast-clint") {
simif->fast_clint = true;
}
if (arg == "+spike-verbose") {
p->enable_log_commits();
}
}
if (loadmem_file != "" && tcm_size > 0)
simif->loadmem(tcm_base, loadmem_file.c_str());
p->reset();
p->get_state()->pc = reset_vector;
@@ -296,11 +345,22 @@ extern "C" void spike_tile(int hartid, char* isa,
tile_t* tile = tiles[hartid];
chipyard_simif_t* simif = tile->simif;
processor_t* proc = tile->proc;
#if defined(SPIKETILE_HTIF_TSI)
if (!simif->htif && tsi)
simif->htif = tsi;
#endif
#if defined(SPIKETILE_HTIF_DTM)
if (!simif->htif && dtm)
simif->htif = dtm;
#endif
simif->cycle = cycle;
if (debug) {
proc->halt_request = proc->HR_REGULAR;
}
if (!debug && proc->halt_request != proc->HR_NONE) {
proc->halt_request = proc->HR_NONE;
}
proc->get_state()->mip->backdoor_write_with_mask(MIP_MTIP, mtip ? MIP_MTIP : 0);
proc->get_state()->mip->backdoor_write_with_mask(MIP_MSIP, msip ? MIP_MSIP : 0);
@@ -309,6 +369,7 @@ extern "C" void spike_tile(int hartid, char* isa,
tile->max_insns = ipc;
uint64_t pre_insns = proc->get_state()->minstret->read();
simif->accessed_tofrom_host = false;
tile->spike_context.switch_to();
*insns_retired = proc->get_state()->minstret->read() - pre_insns;
if (simif->use_stq) {
@@ -357,6 +418,13 @@ extern "C" void spike_tile(int hartid, char* isa,
if (mmio_d_valid) {
simif->mmio_d(mmio_d_data);
}
if (tcm_a_valid) {
simif->tcm_a(tcm_a_address, tcm_a_data, tcm_a_mask, tcm_a_opcode, tcm_a_size);
}
if (tcm_d_ready) {
*tcm_d_valid = simif->tcm_d((uint64_t*)tcm_d_data);
}
}
@@ -369,14 +437,35 @@ chipyard_simif_t::chipyard_simif_t(size_t icache_ways,
char* readonly_uncacheable,
char* executable,
size_t ic_sourceids,
size_t dc_sourceids
size_t dc_sourceids,
size_t tcm_base,
size_t tcm_size,
const char* isastr,
size_t pmpregions
) :
cycle(0),
use_stq(false),
htif(nullptr),
fast_clint(false),
cfg(std::make_pair(0, 0),
nullptr,
isastr,
"MSU",
"vlen:128,elen:64",
false,
endianness_little,
pmpregions,
std::vector<mem_cfg_t>(),
std::vector<size_t>(),
false,
0),
accessed_tofrom_host(false),
icache_ways(icache_ways),
icache_sets(icache_sets),
dcache_ways(dcache_ways),
dcache_sets(dcache_sets),
tcm_base(tcm_base),
tcm_size(tcm_size),
mmio_valid(false),
mmio_inflight(false)
{
@@ -432,6 +521,14 @@ chipyard_simif_t::chipyard_simif_t(size_t icache_ways,
uint64_t size_int = std::stoul(size);
executables.push_back(mem_region_t { base_int, size_int });
}
tcm = (uint8_t*)malloc(tcm_size);
}
void chipyard_simif_t::flush_icache() {
for (auto &w : icache) {
for (size_t i = 0; i < icache_sets; i++) w[i].state = NONE;
}
}
bool chipyard_simif_t::reservable(reg_t addr) {
@@ -440,12 +537,20 @@ bool chipyard_simif_t::reservable(reg_t addr) {
return true;
}
}
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
return true;
}
return false;
}
bool chipyard_simif_t::mmio_fetch(reg_t addr, size_t len, uint8_t* bytes) {
bool executable = false;
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
memcpy(bytes, tcm + addr - tcm_base, len);
return true;
}
for (auto& r: executables) {
if (addr >= r.base && addr + len <= r.base + r.size) {
executable = true;
@@ -466,6 +571,16 @@ bool chipyard_simif_t::mmio_load(reg_t addr, size_t len, uint8_t* bytes) {
bool found = false;
bool cacheable = false;
bool readonly = false;
reg_t tohost_addr = htif ? htif->get_tohost_addr() : 0;
reg_t fromhost_addr = htif ? htif->get_fromhost_addr() : 0;
if (addr == tohost_addr || addr == fromhost_addr) {
accessed_tofrom_host = true;
}
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
memcpy(bytes, tcm + addr - tcm_base, len);
return true;
}
for (auto& r: cacheables) {
if (addr >= r.base && addr + len <= r.base + r.size) {
cacheable = true;
@@ -497,6 +612,8 @@ bool chipyard_simif_t::mmio_load(reg_t addr, size_t len, uint8_t* bytes) {
while (!handle_cache_access(addr, len, bytes, nullptr, LOAD)) {
host->switch_to();
}
uint64_t lddata = 0;
memcpy(&lddata, bytes, len);
} else {
handle_mmio_access(addr, len, bytes, nullptr, LOAD, readonly);
}
@@ -523,6 +640,7 @@ void chipyard_simif_t::handle_mmio_access(reg_t addr, size_t len,
mmio_st = type == STORE;
if (type == STORE) {
assert(len <= 8);
mmio_stdata = 0;
memcpy(&mmio_stdata, store_bytes, len);
}
mmio_len = len;
@@ -829,9 +947,21 @@ bool chipyard_simif_t::dcache_c(uint64_t* address, uint64_t* source, int* param,
}
bool chipyard_simif_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes) {
reg_t tohost_addr = htif ? htif->get_tohost_addr() : 0;
reg_t fromhost_addr = htif ? htif->get_fromhost_addr() : 0;
if (addr == tohost_addr || addr == fromhost_addr) {
accessed_tofrom_host = true;
}
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
memcpy(tcm + addr - tcm_base, bytes, len);
return true;
}
bool found = false;
bool cacheable = false;
for (auto& r: cacheables) {
for (auto& r: cacheables) {
if (addr >= r.base && addr + len <= r.base + r.size) {
cacheable = true;
found = true;
@@ -849,6 +979,8 @@ bool chipyard_simif_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes)
return false;
}
if (cacheable) {
uint64_t temp = 0;
memcpy(&temp, bytes, len);
if (use_stq) {
assert(len <= 8);
uint64_t stdata;
@@ -899,27 +1031,104 @@ void chipyard_simif_t::dcache_d(uint64_t sourceid, uint64_t data[8], unsigned ch
}
}
void chipyard_simif_t::tcm_a(uint64_t address, uint64_t data, uint32_t mask, uint32_t opcode, uint32_t size) {
bool load = opcode == 4;
uint64_t rdata = 0;
memcpy(&rdata, tcm + address - tcm_base, 8);
tcm_q.push_back(rdata);
if (!load) {
for (size_t i = 0; i < 8; i++) {
if ((mask >> i) & 1) {
memcpy(tcm + address - tcm_base + i, ((uint8_t*)&data) + i, 1);
}
}
}
}
bool chipyard_simif_t::tcm_d(uint64_t* data) {
if (tcm_q.size() == 0)
return false;
*data = tcm_q[0];
tcm_q.erase(tcm_q.begin());
return true;
}
void chipyard_simif_t::loadmem(size_t base, const char* fname) {
class loadmem_memif_t : public memif_t {
public:
loadmem_memif_t(chipyard_simif_t* _simif, size_t _start) : memif_t(nullptr), simif(_simif), start(_start) {}
void write(addr_t taddr, size_t len, const void* src) override
{
addr_t addr = taddr - start;
memcpy(simif->tcm + addr, src, len);
}
void read(addr_t taddr, size_t len, void* bytes) override {
assert(false);
}
endianness_t get_target_endianness() const override {
return endianness_little;
}
private:
chipyard_simif_t* simif;
size_t start;
} loadmem_memif(this, tcm_base);
reg_t entry;
load_elf(fname, &loadmem_memif, &entry);
}
bool insn_should_fence(uint64_t bits) {
uint8_t opcode = bits & 0x7f;
return opcode == 0b0101111 || opcode == 0b0001111;
}
bool insn_is_wfi(uint64_t bits) {
return bits == 0x10500073;
}
void spike_thread_main(void* arg)
{
tile_t* tile = (tile_t*) arg;
processor_t* proc = tile->proc;
chipyard_simif_t* simif = tile->simif;
state_t* state = proc->get_state();
while (true) {
while (tile->max_insns == 0) {
host->switch_to();
}
while (tile->max_insns != 0) {
// TODO: Fences don't work
// uint64_t last_bits = tile->proc->get_last_bits();
// if (insn_should_fence(last_bits) && !tile->simif->stq_empty()) {
//uint64_t last_bits = proc->get_last_bits();
// if (insn_should_fence(last_bits) && !simif->stq_empty()) {
// host->switch_to();
// }
tile->proc->step(1);
uint64_t old_minstret = state->minstret->read();
proc->step(1);
tile->max_insns--;
tile->proc->get_state()->mcycle->write(tile->simif->cycle);
if (proc->is_waiting_for_interrupt()) {
if (simif->fast_clint) {
state->mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP);
tile->max_insns = tile->max_insns <= 1 ? 0 : 1;
} else {
tile->max_insns = 0;
}
}
if (state->debug_mode) {
// TODO: Fix. This needs to apply the same hack as rocket-chip...
// JALRs in debug mode should flush the ICache.
// There is no API to determine if a JALR was executed, so hack the
// pc of the JALR in the debug rom here instead.
if (state->pc == 0x838) {
simif->flush_icache();
}
}
// If we get stuck in WFI, or we start polling tohost/fromhost, switch to host thread
if ((old_minstret == state->minstret->read()) || simif->accessed_tofrom_host) {
tile->max_insns = 0;
}
state->mcycle->write(simif->cycle);
}
}
}

View File

@@ -16,7 +16,8 @@ import "DPI-C" function void cospike_cosim(input longint cycle,
input bit raise_exception,
input bit raise_interrupt,
input longint cause,
input longint wdata
input longint wdata,
input int priv
);
@@ -42,6 +43,7 @@ module SpikeCosim #(
input [63:0] trace_0_cause,
input trace_0_has_wdata,
input [63:0] trace_0_wdata,
input [2:0] trace_0_priv,
input trace_1_valid,
input [63:0] trace_1_iaddr,
@@ -50,7 +52,8 @@ module SpikeCosim #(
input trace_1_interrupt,
input [63:0] trace_1_cause,
input trace_1_has_wdata,
input [63:0] trace_1_wdata
input [63:0] trace_1_wdata,
input [2:0] trace_1_priv
);
initial begin
@@ -62,12 +65,12 @@ module SpikeCosim #(
if (trace_0_valid || trace_0_exception || trace_0_cause) begin
cospike_cosim(cycle, hartid, trace_0_has_wdata, trace_0_valid, trace_0_iaddr,
trace_0_insn, trace_0_exception, trace_0_interrupt, trace_0_cause,
trace_0_wdata);
trace_0_wdata, trace_0_priv);
end
if (trace_1_valid || trace_1_exception || trace_1_cause) begin
cospike_cosim(cycle, hartid, trace_1_has_wdata, trace_1_valid, trace_1_iaddr,
trace_1_insn, trace_1_exception, trace_1_interrupt, trace_1_cause,
trace_1_wdata);
trace_1_wdata, trace_1_priv);
end
end
end

View File

@@ -13,6 +13,8 @@ import "DPI-C" function void spike_tile(input int hartid,
input string executable,
input int icache_sourceids,
input int dcache_sourceids,
input longint tcm_base,
input longint tcm_size,
input longint reset_vector,
input longint ipc,
input longint cycle,
@@ -89,7 +91,18 @@ import "DPI-C" function void spike_tile(input int hartid,
output int mmio_a_size,
input bit mmio_d_valid,
input longint mmio_d_data
input longint mmio_d_data,
input bit tcm_a_valid,
input longint tcm_a_address,
input longint tcm_a_data,
input int tcm_a_mask,
input int tcm_a_opcode,
input int tcm_a_size,
output bit tcm_d_valid,
input bit tcm_d_ready,
output longint tcm_d_data
);
@@ -106,7 +119,9 @@ module SpikeBlackBox #(
parameter READONLY_UNCACHEABLE,
parameter EXECUTABLE,
parameter ICACHE_SOURCEIDS,
parameter DCACHE_SOURCEIDS )(
parameter DCACHE_SOURCEIDS,
parameter TCM_BASE,
parameter TCM_SIZE)(
input clock,
input reset,
input [63:0] reset_vector,
@@ -185,7 +200,18 @@ module SpikeBlackBox #(
output [31:0] mmio_a_size,
input mmio_d_valid,
input [63:0] mmio_d_data
input [63:0] mmio_d_data,
input tcm_a_valid,
input [63:0] tcm_a_address,
input [63:0] tcm_a_data,
input [31:0] tcm_a_mask,
input [31:0] tcm_a_opcode,
input [31:0] tcm_a_size,
output tcm_d_valid,
input tcm_d_ready,
output [63:0] tcm_d_data
);
longint __insns_retired;
@@ -257,7 +283,13 @@ module SpikeBlackBox #(
reg [63:0] __dcache_c_data_6_reg;
reg [63:0] __dcache_c_data_7_reg;
wire __tcm_d_ready;
bit __tcm_d_valid;
longint __tcm_d_data;
reg __tcm_d_valid_reg;
reg [63:0] __tcm_d_data_reg;
always @(posedge clock) begin
@@ -322,12 +354,18 @@ module SpikeBlackBox #(
__dcache_c_data_6_reg <= 64'h0;
__dcache_c_data_7 = 64'h0;
__dcache_c_data_7_reg <= 64'h0;
__tcm_d_valid = 1'b0;
__tcm_d_valid_reg <= 1'b0;
__tcm_d_data = 64'h0;
__tcm_d_data_reg <= 64'h0;
spike_tile_reset(HARTID);
end else begin
spike_tile(HARTID, ISA, PMPREGIONS,
ICACHE_SETS, ICACHE_WAYS, DCACHE_SETS, DCACHE_WAYS,
CACHEABLE, UNCACHEABLE, READONLY_UNCACHEABLE, EXECUTABLE,
ICACHE_SOURCEIDS, DCACHE_SOURCEIDS,
TCM_BASE, TCM_SIZE,
reset_vector, ipc, cycle, __insns_retired,
debug, mtip, msip, meip, seip,
@@ -350,7 +388,10 @@ module SpikeBlackBox #(
dcache_d_data_4, dcache_d_data_5, dcache_d_data_6, dcache_d_data_7,
__mmio_a_ready, __mmio_a_valid, __mmio_a_address, __mmio_a_data, __mmio_a_store, __mmio_a_size,
mmio_d_valid, mmio_d_data
mmio_d_valid, mmio_d_data,
tcm_a_valid, tcm_a_address, tcm_a_data, tcm_a_mask, tcm_a_opcode, tcm_a_size,
__tcm_d_valid, __tcm_d_ready, __tcm_d_data
);
__insns_retired_reg <= __insns_retired;
@@ -385,6 +426,10 @@ module SpikeBlackBox #(
__mmio_a_data_reg <= __mmio_a_data;
__mmio_a_store_reg <= __mmio_a_store;
__mmio_a_size_reg <= __mmio_a_size;
__tcm_d_valid_reg <= __tcm_d_valid;
__tcm_d_data_reg <= __tcm_d_data;
end
end // always @ (posedge clock)
assign insns_retired = __insns_retired_reg;
@@ -424,6 +469,8 @@ module SpikeBlackBox #(
assign mmio_a_size = __mmio_a_size_reg;
assign __mmio_a_ready = mmio_a_ready;
assign tcm_d_valid = __tcm_d_valid_reg;
assign tcm_d_data = __tcm_d_data_reg;
assign __tcm_d_ready = tcm_d_ready;
endmodule;

View File

@@ -6,7 +6,7 @@ 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 org.chipsalliance.cde.config.{Parameters, Field}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, LazyRawModuleImp, LazyModuleImpLike, BindingScope}
import freechips.rocketchip.util.{ResetCatchAndSync}
import chipyard.iobinders._

View File

@@ -0,0 +1,19 @@
package chipyard
import org.reflections.Reflections
import org.reflections.scanners.Scanners.SubTypes
import scala.jdk.CollectionConverters._
import scala.collection.{SortedSet}
import org.chipsalliance.cde.config.{Config}
object ConfigFinder {
def main(args: Array[String]) = {
val reflections = new Reflections()
val classes = reflections.get(SubTypes.of(classOf[Config]).asClass()).asScala
val sortedClasses = SortedSet[String]() ++ classes.map(_.getName)
for (cls <- sortedClasses) {
println(cls)
}
}
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.experimental.{IntParam, StringParam, IO}
import chisel3.util._
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.devices.tilelink._
@@ -18,7 +18,8 @@ case class SpikeCosimConfig(
mem0_base: BigInt,
mem0_size: BigInt,
nharts: Int,
bootrom: String
bootrom: String,
has_dtm: Boolean
)
class SpikeCosim(cfg: SpikeCosimConfig) extends BlackBox(Map(
@@ -32,6 +33,7 @@ class SpikeCosim(cfg: SpikeCosimConfig) extends BlackBox(Map(
{
addResource("/csrc/cospike.cc")
addResource("/vsrc/cospike.v")
if (cfg.has_dtm) addResource("/csrc/cospike_dtm.h")
val io = IO(new Bundle {
val clock = Input(Clock())
val reset = Input(Bool())
@@ -46,6 +48,7 @@ class SpikeCosim(cfg: SpikeCosimConfig) extends BlackBox(Map(
val cause = UInt(64.W)
val has_wdata = Bool()
val wdata = UInt(64.W)
val priv = UInt(3.W)
}))
})
}
@@ -64,12 +67,8 @@ object SpikeCosim
require(trace.numInsns <= 2)
cosim.io.cycle := cycle
cosim.io.trace.map(t => {
t := DontCare
t.valid := false.B
t.iaddr := 0.U
t.insn := 0.U
t.exception := false.B
t.interrupt := false.B
t.cause := 0.U
})
cosim.io.hartid := hartid.U
for (i <- 0 until trace.numInsns) {
@@ -83,6 +82,7 @@ object SpikeCosim
cosim.io.trace(i).cause := trace.insns(i).cause
cosim.io.trace(i).has_wdata := trace.insns(i).wdata.isDefined.B
cosim.io.trace(i).wdata := trace.insns(i).wdata.getOrElse(0.U)
cosim.io.trace(i).priv := trace.insns(i).priv
}
}
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.system._
import freechips.rocketchip.config.Parameters
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.devices.tilelink._
// ------------------------------------
@@ -14,7 +14,7 @@ import freechips.rocketchip.devices.tilelink._
// DOC include start: DigitalTop
class DigitalTop(implicit p: Parameters) extends ChipyardSystem
with testchipip.CanHavePeripheryCustomBootPin // Enables optional custom boot pin
with testchipip.HasPeripheryBootAddrReg // Use programmable boot address register
with testchipip.CanHavePeripheryBootAddrReg // Use programmable boot address register
with testchipip.CanHaveTraceIO // Enables optionally adding trace IO
with testchipip.CanHaveBackingScratchpad // Enables optionally adding a backing scratchpad
with testchipip.CanHavePeripheryBlockDevice // Enables optionally adding the block device

View File

@@ -3,7 +3,7 @@ package chipyard.iobinders
import chisel3._
import chisel3.experimental.{Analog, IO, DataMirror}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.devices.debug._
import freechips.rocketchip.jtag.{JTAGIO}
@@ -25,7 +25,6 @@ import barstools.iocell.chisel._
import testchipip._
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
import chipyard.{CanHaveMasterTLMemPort}
import chipyard.clocking.{HasChipyardPRCI, DividerOnlyClockGenerator}
import scala.reflect.{ClassTag}
@@ -51,6 +50,12 @@ case object IOBinders extends Field[Map[String, Seq[IOBinderFunction]]](
Map[String, Seq[IOBinderFunction]]().withDefaultValue(Nil)
)
case object DontTouchIOBindersPorts extends Field[Boolean](true)
class WithDontTouchIOBinders(b: Boolean = true) extends Config((site, here, up) => {
case DontTouchIOBindersPorts => b
})
abstract trait HasIOBinders { this: LazyModule =>
val lazySystem: LazyModule
private val iobinders = p(IOBinders)
@@ -67,10 +72,33 @@ abstract trait HasIOBinders { this: LazyModule =>
})
// A publicly accessible list of IO cells (useful for a floorplanning tool, for example)
lazy val iocells = (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer
val iocells = InModuleBody { (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer }
// A mapping between stringified DigitalSystem traits and their corresponding ChipTop ports
lazy val portMap = iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap
val portMap = InModuleBody { iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap }
// A mapping between stringified DigitalSystem traits and their corresponding ChipTop iocells
val iocellMap = InModuleBody { iobinders.keys.map(k => k -> (lzyFlattened(k)._2 ++ impFlattened(k)._2)).toMap }
InModuleBody {
if (p(DontTouchIOBindersPorts)) {
portMap.values.foreach(_.foreach(dontTouch(_)))
}
println("IOCells generated by IOBinders:")
for ((k, v) <- iocellMap) {
if (!v.isEmpty) {
val cells = v.map(_.getClass.getSimpleName).groupBy(identity).mapValues(_.size)
println(s" IOBinder for $k generated:")
for ((t, c) <- cells) { println(s" $c X $t") }
}
}
println()
val totals = iocells.map(_.getClass.getSimpleName).groupBy(identity).mapValues(_.size)
println(s" Total generated ${iocells.size} IOCells:")
for ((t, c) <- totals) { println(s" $c X $t") }
}
}
// Note: The parameters instance is accessible only through LazyModule
@@ -219,7 +247,7 @@ class WithDebugIOCells extends OverrideLazyIOBinder({
def clockBundle = clockSinkNode.get.in.head._1
InModuleBody { system.asInstanceOf[BaseSubsystem].module match { case system: HasPeripheryDebugModuleImp => {
InModuleBody { system.asInstanceOf[BaseSubsystem] match { case system: HasPeripheryDebug => {
system.debug.map({ debug =>
// We never use the PSDIO, so tie it off on-chip
system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) }
@@ -396,45 +424,4 @@ class WithDontTouchPorts extends OverrideIOBinder({
(system: DontTouch) => system.dontTouchPorts(); (Nil, Nil)
})
class ClockWithFreq(val freqMHz: Double) extends Bundle {
val clock = Clock()
}
class WithDividerOnlyClockGenerator extends OverrideLazyIOBinder({
(system: HasChipyardPRCI) => {
// Connect the implicit clock
implicit val p = GetSystemParameters(system)
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
system.connectImplicitClockSinkNode(implicitClockSinkNode)
InModuleBody {
val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset
system.asInstanceOf[BaseSubsystem].module match { case l: LazyModuleImp => {
l.clock := implicit_clock
l.reset := implicit_reset
}}
}
// Connect all other requested clocks
val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
val dividerOnlyClockGen = LazyModule(new DividerOnlyClockGenerator("buildTopClockGenerator"))
(system.allClockGroupsNode
:= dividerOnlyClockGen.node
:= referenceClockSource)
InModuleBody {
val clock_wire = Wire(Input(new ClockWithFreq(dividerOnlyClockGen.module.referenceFreq)))
val reset_wire = Wire(Input(AsyncReset()))
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey))
referenceClockSource.out.unzip._1.map { o =>
o.clock := clock_wire.clock
o.reset := reset_wire
}
(Seq(clock_io, reset_io), clockIOCell ++ resetIOCell)
}
}
})

View File

@@ -4,9 +4,10 @@ import chisel3._
import chisel3.util._
import chisel3.experimental.{IntParam, StringParam, IO}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.devices.debug.{ExportDebug, DMI}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.rocket._
import freechips.rocketchip.tilelink._
@@ -15,8 +16,7 @@ import freechips.rocketchip.util._
import freechips.rocketchip.tile._
import freechips.rocketchip.prci.ClockSinkParameters
case class SpikeCoreParams(
) extends CoreParams {
case class SpikeCoreParams() extends CoreParams {
val useVM = true
val useHypervisor = false
val useSupervisor = true
@@ -79,7 +79,8 @@ case class SpikeTileParams(
hartId: Int = 0,
val core: SpikeCoreParams = SpikeCoreParams(),
icacheParams: ICacheParams = ICacheParams(nWays = 32),
dcacheParams: DCacheParams = DCacheParams(nWays = 32)
dcacheParams: DCacheParams = DCacheParams(nWays = 32),
tcmParams: Option[MasterPortParams] = None // tightly coupled memory
) extends InstantiableTileParams[SpikeTile]
{
val name = Some("spike_tile")
@@ -145,6 +146,27 @@ class SpikeTile(
sourceId = IdRange(0, 1),
requestFifo = true))))))
tlSlaveXbar.node :*= slaveNode
val tcmNode = spikeTileParams.tcmParams.map { tcmP =>
val device = new MemoryDevice
val base = AddressSet.misaligned(tcmP.base, tcmP.size)
val tcmNode = TLManagerNode(Seq(TLSlavePortParameters.v1(
managers = Seq(TLSlaveParameters.v1(
address = base,
resources = device.reg,
regionType = RegionType.IDEMPOTENT, // not cacheable
executable = true,
supportsGet = TransferSizes(1, 8),
supportsPutFull = TransferSizes(1, 8),
supportsPutPartial = TransferSizes(1, 8),
fifoId = Some(0)
)),
beatBytes = 8
)))
connectTLSlave(tcmNode := TLBuffer(), 8)
tcmNode
}
tlOtherMastersNode := TLBuffer() := tlMasterXbar.node
masterNode :=* tlOtherMastersNode
tlMasterXbar.node := TLWidthWidget(64) := TLBuffer():= icacheNode
@@ -166,7 +188,10 @@ class SpikeBlackBox(
cacheable_regions: String,
uncacheable_regions: String,
readonly_uncacheable_regions: String,
executable_regions: String) extends BlackBox(Map(
executable_regions: String,
tcm_base: BigInt,
tcm_size: BigInt,
use_dtm: Boolean) extends BlackBox(Map(
"HARTID" -> IntParam(hartId),
"ISA" -> StringParam(isa),
"PMPREGIONS" -> IntParam(pmpregions),
@@ -179,7 +204,9 @@ class SpikeBlackBox(
"UNCACHEABLE" -> StringParam(uncacheable_regions),
"READONLY_UNCACHEABLE" -> StringParam(readonly_uncacheable_regions),
"CACHEABLE" -> StringParam(cacheable_regions),
"EXECUTABLE" -> StringParam(executable_regions)
"EXECUTABLE" -> StringParam(executable_regions),
"TCM_BASE" -> IntParam(tcm_base),
"TCM_SIZE" -> IntParam(tcm_size)
)) with HasBlackBoxResource {
val io = IO(new Bundle {
@@ -258,10 +285,30 @@ class SpikeBlackBox(
val data = Input(UInt(64.W))
}
}
val tcm = new Bundle {
val a = new Bundle {
val valid = Input(Bool())
val address = Input(UInt(64.W))
val data = Input(UInt(64.W))
val mask = Input(UInt(32.W))
val opcode = Input(UInt(32.W))
val size = Input(UInt(32.W))
}
val d = new Bundle {
val valid = Output(Bool())
val ready = Input(Bool())
val data = Output(UInt(64.W))
}
}
})
addResource("/vsrc/spiketile.v")
addResource("/csrc/spiketile.cc")
if (use_dtm) {
addResource("/csrc/spiketile_dtm.h")
} else {
addResource("/csrc/spiketile_tsi.h")
}
}
class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
@@ -285,11 +332,19 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
val (dcache_tl, dcacheEdge) = outer.dcacheNode.out(0)
val (mmio_tl, mmioEdge) = outer.mmioNode.out(0)
// Note: This assumes that if the debug module exposes the ClockedDMI port,
// then the DTM-based bringup with SimDTM will be used. This isn't required to be
// true, but it usually is
val useDTM = p(ExportDebug).protocols.contains(DMI)
val spike = Module(new SpikeBlackBox(hartId, isaDTS, tileParams.core.nPMPs,
tileParams.icache.get.nSets, tileParams.icache.get.nWays,
tileParams.dcache.get.nSets, tileParams.dcache.get.nWays,
tileParams.dcache.get.nMSHRs,
cacheable_regions, uncacheable_regions, readonly_uncacheable_regions, executable_regions))
cacheable_regions, uncacheable_regions, readonly_uncacheable_regions, executable_regions,
outer.spikeTileParams.tcmParams.map(_.base).getOrElse(0),
outer.spikeTileParams.tcmParams.map(_.size).getOrElse(0),
useDTM
))
spike.io.clock := clock.asBool
val cycle = RegInit(0.U(64.W))
cycle := cycle + 1.U
@@ -304,64 +359,63 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
spike.io.msip := int_bundle.msip
spike.io.meip := int_bundle.meip
spike.io.seip := int_bundle.seip.get
spike.io.ipc := PlusArg("spike-ipc", 10000, width=64)
spike.io.ipc := PlusArg("spike-ipc", width=32, default=10000)
val blockBits = log2Ceil(p(CacheBlockBytes))
val icache_a_q = Module(new Queue(new TLBundleA(icacheEdge.bundle), 1, flow=true, pipe=true))
spike.io.icache.a.ready := icache_a_q.io.enq.ready && icache_a_q.io.count === 0.U
icache_tl.a <> icache_a_q.io.deq
icache_a_q.io.enq.valid := spike.io.icache.a.valid
icache_a_q.io.enq.bits := icacheEdge.Get(
spike.io.icache.a.ready := icache_tl.a.ready
icache_tl.a.valid := spike.io.icache.a.valid
icache_tl.a.bits := icacheEdge.Get(
fromSource = spike.io.icache.a.sourceid,
toAddress = (spike.io.icache.a.address >> blockBits) << blockBits,
lgSize = blockBits.U)._2
icache_tl.d.ready := true.B
spike.io.icache.d.valid := icache_tl.d.valid
spike.io.icache.d.sourceid := icache_tl.d.bits.source
spike.io.icache.d.data := icache_tl.d.bits.data.asTypeOf(Vec(8, UInt(64.W)))
val dcache_a_q = Module(new Queue(new TLBundleA(dcacheEdge.bundle), 1, flow=true, pipe=true))
spike.io.dcache.a.ready := dcache_a_q.io.enq.ready && dcache_a_q.io.count === 0.U
dcache_tl.a <> dcache_a_q.io.deq
dcache_a_q.io.enq.valid := spike.io.dcache.a.valid
dcache_a_q.io.enq.bits := dcacheEdge.AcquireBlock(
fromSource = spike.io.dcache.a.sourceid,
toAddress = (spike.io.dcache.a.address >> blockBits) << blockBits,
lgSize = blockBits.U,
growPermissions = Mux(spike.io.dcache.a.state_old, 2.U, Mux(spike.io.dcache.a.state_new, 1.U, 0.U)))._2
spike.io.dcache.a.ready := dcache_tl.a.ready
dcache_tl.a.valid := spike.io.dcache.a.valid
if (dcacheEdge.manager.anySupportAcquireB) {
dcache_tl.a.bits := dcacheEdge.AcquireBlock(
fromSource = spike.io.dcache.a.sourceid,
toAddress = (spike.io.dcache.a.address >> blockBits) << blockBits,
lgSize = blockBits.U,
growPermissions = Mux(spike.io.dcache.a.state_old, 2.U, Mux(spike.io.dcache.a.state_new, 1.U, 0.U)))._2
} else {
dcache_tl.a.bits := DontCare
}
dcache_tl.b.ready := true.B
spike.io.dcache.b.valid := dcache_tl.b.valid
spike.io.dcache.b.address := dcache_tl.b.bits.address
spike.io.dcache.b.source := dcache_tl.b.bits.source
spike.io.dcache.b.param := dcache_tl.b.bits.param
val dcache_c_q = Module(new Queue(new TLBundleC(dcacheEdge.bundle), 1, flow=true, pipe=true))
spike.io.dcache.c.ready := dcache_c_q.io.enq.ready && dcache_c_q.io.count === 0.U
dcache_tl.c <> dcache_c_q.io.deq
dcache_c_q.io.enq.valid := spike.io.dcache.c.valid
dcache_c_q.io.enq.bits := Mux(spike.io.dcache.c.voluntary,
dcacheEdge.Release(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
shrinkPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt)._2,
Mux(spike.io.dcache.c.has_data,
dcacheEdge.ProbeAck(
spike.io.dcache.c.ready := dcache_tl.c.ready
dcache_tl.c.valid := spike.io.dcache.c.valid
if (dcacheEdge.manager.anySupportAcquireB) {
dcache_tl.c.bits := Mux(spike.io.dcache.c.voluntary,
dcacheEdge.Release(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt),
dcacheEdge.ProbeAck(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param)
))
shrinkPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt)._2,
Mux(spike.io.dcache.c.has_data,
dcacheEdge.ProbeAck(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt),
dcacheEdge.ProbeAck(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param)
))
} else {
dcache_tl.c.bits := DontCare
}
val has_data = dcacheEdge.hasData(dcache_tl.d.bits)
val should_finish = dcacheEdge.isRequest(dcache_tl.d.bits)
@@ -376,12 +430,10 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
dcache_tl.e.valid := dcache_tl.d.valid && should_finish
dcache_tl.e.bits := dcacheEdge.GrantAck(dcache_tl.d.bits)
val mmio_a_q = Module(new Queue(new TLBundleA(mmioEdge.bundle), 1, flow=true, pipe=true))
spike.io.mmio.a.ready := mmio_a_q.io.enq.ready && mmio_a_q.io.count === 0.U
mmio_tl.a <> mmio_a_q.io.deq
mmio_a_q.io.enq.valid := spike.io.mmio.a.valid
val log_size = MuxCase(0.U, (0 until 3).map { i => (spike.io.mmio.a.size === (1 << i).U) -> i.U })
mmio_a_q.io.enq.bits := Mux(spike.io.mmio.a.store,
spike.io.mmio.a.ready := mmio_tl.a.ready
mmio_tl.a.valid := spike.io.mmio.a.valid
val log_size = (0 until 4).map { i => Mux(spike.io.mmio.a.size === (1 << i).U, i.U, 0.U) }.reduce(_|_)
mmio_tl.a.bits := Mux(spike.io.mmio.a.store,
mmioEdge.Put(0.U, spike.io.mmio.a.address, log_size, spike.io.mmio.a.data)._2,
mmioEdge.Get(0.U, spike.io.mmio.a.address, log_size)._2)
@@ -389,9 +441,33 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
spike.io.mmio.d.valid := mmio_tl.d.valid
spike.io.mmio.d.data := mmio_tl.d.bits.data
spike.io.tcm := DontCare
spike.io.tcm.a.valid := false.B
spike.io.tcm.d.ready := true.B
outer.tcmNode.map { tcmNode =>
val (tcm_tl, tcmEdge) = tcmNode.in(0)
val debug_tcm_tl = WireInit(tcm_tl)
dontTouch(debug_tcm_tl)
tcm_tl.a.ready := true.B
spike.io.tcm.a.valid := tcm_tl.a.valid
spike.io.tcm.a.address := tcm_tl.a.bits.address
spike.io.tcm.a.data := tcm_tl.a.bits.data
spike.io.tcm.a.mask := tcm_tl.a.bits.mask
spike.io.tcm.a.opcode := tcm_tl.a.bits.opcode
spike.io.tcm.a.size := tcm_tl.a.bits.size
spike.io.tcm.d.ready := tcm_tl.d.ready
tcm_tl.d.bits := tcmEdge.AccessAck(RegNext(tcm_tl.a.bits))
when (RegNext(tcm_tl.a.bits.opcode === TLMessages.Get)) {
tcm_tl.d.bits.opcode := TLMessages.AccessAckData
}
tcm_tl.d.valid := spike.io.tcm.d.valid
tcm_tl.d.bits.data := spike.io.tcm.d.data
}
}
class WithNSpikeCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
class WithNSpikeCores(n: Int = 1, tileParams: SpikeTileParams = SpikeTileParams(),
overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => {
// Calculate the next available hart ID (since hart ID cannot be duplicated)
val prev = up(TilesLocated(InSubsystem), site)
@@ -399,8 +475,21 @@ class WithNSpikeCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends
// Create TileAttachParams for every core to be instantiated
(0 until n).map { i =>
SpikeTileAttachParams(
tileParams = SpikeTileParams(hartId = i + idOffset)
tileParams = tileParams.copy(hartId = i + idOffset)
)
} ++ prev
}
})
class WithSpikeTCM extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => {
val prev = up(TilesLocated(InSubsystem))
require(prev.size == 1)
val spike = prev(0).asInstanceOf[SpikeTileAttachParams]
Seq(spike.copy(tileParams = spike.tileParams.copy(
tcmParams = Some(up(ExtMem).get.master)
)))
}
case ExtMem => None
case BankedL2Key => up(BankedL2Key).copy(nBanks = 0)
})

View File

@@ -9,9 +9,10 @@ import chisel3._
import chisel3.internal.sourceinfo.{SourceInfo}
import freechips.rocketchip.prci._
import freechips.rocketchip.config.{Field, Parameters}
import org.chipsalliance.cde.config.{Field, Parameters}
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp, ExportDebug, DebugModuleKey}
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, ExportDebug, DebugModuleKey}
import sifive.blocks.devices.uart.{HasPeripheryUART, PeripheryUARTKey}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tile._
import freechips.rocketchip.tilelink._
@@ -45,9 +46,35 @@ trait CanHaveHTIF { this: BaseSubsystem =>
}
}
// This trait adds the "chosen" node to DTS, which
// can be used to pass information to OS about the earlycon
case object ChosenInDTS extends Field[Boolean](true)
trait CanHaveChosenInDTS { this: BaseSubsystem =>
if (p(ChosenInDTS)) {
this match {
case t: HasPeripheryUART if (!p(PeripheryUARTKey).isEmpty) => {
val chosen = new Device {
def describe(resources: ResourceBindings): Description = {
val stdout = resources("stdout").map(_.value)
Description("chosen", resources("uart").headOption.map { case Binding(_, value) =>
"stdout-path" -> Seq(value)
}.toMap)
}
}
ResourceBinding {
t.uarts.foreach(u => Resource(chosen, "uart").bind(ResourceAlias(u.device.label)))
}
}
case _ =>
}
}
}
class ChipyardSubsystem(implicit p: Parameters) extends BaseSubsystem
with HasTiles
with HasPeripheryDebug
with CanHaveHTIF
with CanHaveChosenInDTS
{
def coreMonitorBundles = tiles.map {
case r: RocketTile => r.module.core.rocketImpl.coreMonitorBundle

View File

@@ -7,7 +7,7 @@ package chipyard
import chisel3._
import freechips.rocketchip.config.{Parameters, Field}
import org.chipsalliance.cde.config.{Parameters, Field}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
@@ -31,6 +31,14 @@ class ChipyardSystem(implicit p: Parameters) extends ChipyardSubsystem
val bootROM = p(BootROMLocated(location)).map { BootROM.attach(_, this, CBUS) }
val maskROMs = p(MaskROMLocated(location)).map { MaskROM.attach(_, this, CBUS) }
// If there is no bootrom, the tile reset vector bundle will be tied to zero
if (bootROM.isEmpty) {
val fakeResetVectorSourceNode = BundleBridgeSource[UInt]()
InModuleBody { fakeResetVectorSourceNode.bundle := 0.U }
tileResetVectorNexusNode := fakeResetVectorSourceNode
}
override lazy val module = new ChipyardSystemModule(this)
}

View File

@@ -1,108 +0,0 @@
package chipyard
import chisel3._
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.util.{ResetCatchAndSync}
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters, ClockSinkParameters, ClockParameters}
import chipyard.harness.{ApplyHarnessBinders, HarnessBinders}
import chipyard.iobinders.HasIOBinders
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
// -------------------------------
// Chipyard Test Harness
// -------------------------------
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
case object DefaultClockFrequencyKey extends Field[Double](100.0) // MHz
trait HasHarnessSignalReferences {
implicit val p: Parameters
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
var refClockFreq: Double = p(DefaultClockFrequencyKey)
def setRefClockFreq(freqMHz: Double) = { refClockFreq = freqMHz }
def getRefClockFreq: Double = refClockFreq
def buildtopClock: Clock
def buildtopReset: Reset
def success: Bool
}
class HarnessClockInstantiator {
private val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty
// request a clock bundle at a particular frequency
def requestClockBundle(name: String, freqRequested: Double): ClockBundle = {
val clockBundle = Wire(new ClockBundle(ClockBundleParameters()))
_clockMap(name) = (freqRequested, clockBundle)
clockBundle
}
// connect all clock wires specified to a divider only PLL
def instantiateHarnessDividerPLL(refClock: ClockBundle): Unit = {
val sinks = _clockMap.map({ case (name, (freq, bundle)) =>
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name))
}).toSeq
val pllConfig = new SimplePllConfiguration("harnessDividerOnlyClockGenerator", sinks)
pllConfig.emitSummaries()
val dividedClocks = LinkedHashMap[Int, Clock]()
def instantiateDivider(div: Int): Clock = {
val divider = Module(new ClockDividerN(div))
divider.suggestName(s"ClockDivideBy${div}")
divider.io.clk_in := refClock.clock
dividedClocks(div) = divider.io.clk_out
divider.io.clk_out
}
// connect wires to clock source
for (sinkParams <- sinks) {
// bypass the reference freq. (don't create a divider + reset sync)
val (divClock, divReset) = if (sinkParams.take.get.freqMHz != pllConfig.referenceFreqMHz) {
val div = pllConfig.sinkDividerMap(sinkParams)
val divClock = dividedClocks.getOrElse(div, instantiateDivider(div))
(divClock, ResetCatchAndSync(divClock, refClock.reset.asBool))
} else {
(refClock.clock, refClock.reset)
}
_clockMap(sinkParams.name.get)._2.clock := divClock
_clockMap(sinkParams.name.get)._2.reset := divReset
}
}
}
case object HarnessClockInstantiatorKey extends Field[HarnessClockInstantiator](new HarnessClockInstantiator)
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences {
val io = IO(new Bundle {
val success = Output(Bool())
})
val buildtopClock = Wire(Clock())
val buildtopReset = Wire(Reset())
val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop")
val dut = Module(lazyDut.module)
io.success := false.B
val success = io.success
lazyDut match { case d: HasIOBinders =>
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
}
val refClkBundle = p(HarnessClockInstantiatorKey).requestClockBundle("buildtop_reference_clock", getRefClockFreq * (1000 * 1000))
buildtopClock := refClkBundle.clock
buildtopReset := WireInit(refClkBundle.reset)
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
implicitHarnessClockBundle.clock := clock
implicitHarnessClockBundle.reset := reset
p(HarnessClockInstantiatorKey).instantiateHarnessDividerPLL(implicitHarnessClockBundle)
}

View File

@@ -4,7 +4,7 @@ import scala.collection.mutable.{LinkedHashSet}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tile.{XLen, TileParams}
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.system.{TestGeneration, RegressionTestSuite, RocketTestSuite}
/**

View File

@@ -0,0 +1,123 @@
package chipyard.clocking
import chisel3._
import chisel3.util._
import chipyard.iobinders.{OverrideLazyIOBinder, GetSystemParameters, IOCellKey}
import freechips.rocketchip.prci._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tilelink._
import barstools.iocell.chisel._
class ClockWithFreq(val freqMHz: Double) extends Bundle {
val clock = Clock()
}
// This uses the FakePLL, which uses a ClockAtFreq Verilog blackbox to generate
// the requested clocks. This also adds TileLink ClockDivider and ClockSelector
// blocks, which allow memory-mapped control of clock division, and clock muxing
// between the FakePLL and the slow off-chip clock
// Note: This will not simulate properly with firesim
class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
(system: HasChipyardPRCI) => {
// Connect the implicit clock
implicit val p = GetSystemParameters(system)
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
system.connectImplicitClockSinkNode(implicitClockSinkNode)
InModuleBody {
val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset
system.asInstanceOf[BaseSubsystem].module match { case l: LazyModuleImp => {
l.clock := implicit_clock
l.reset := implicit_reset
}}
}
val tlbus = system.asInstanceOf[BaseSubsystem].locateTLBusWrapper(system.prciParams.slaveWhere)
val baseAddress = system.prciParams.baseAddress
val clockDivider = system.prci_ctrl_domain { LazyModule(new TLClockDivider (baseAddress + 0x20000, tlbus.beatBytes)) }
val clockSelector = system.prci_ctrl_domain { LazyModule(new TLClockSelector(baseAddress + 0x30000, tlbus.beatBytes)) }
val pllCtrl = system.prci_ctrl_domain { LazyModule(new FakePLLCtrl (baseAddress + 0x40000, tlbus.beatBytes)) }
tlbus.toVariableWidthSlave(Some("clock-div-ctrl")) { clockDivider.tlNode := TLBuffer() }
tlbus.toVariableWidthSlave(Some("clock-sel-ctrl")) { clockSelector.tlNode := TLBuffer() }
tlbus.toVariableWidthSlave(Some("pll-ctrl")) { pllCtrl.tlNode := TLBuffer() }
system.allClockGroupsNode := clockDivider.clockNode := clockSelector.clockNode
// Connect all other requested clocks
val slowClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
val pllClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
// The order of the connections to clockSelector.clockNode configures the inputs
// of the clockSelector's clockMux. Default to using the slowClockSource,
// software should enable the PLL, then switch to the pllClockSource
clockSelector.clockNode := slowClockSource
clockSelector.clockNode := pllClockSource
val pllCtrlSink = BundleBridgeSink[FakePLLCtrlBundle]()
pllCtrlSink := pllCtrl.ctrlNode
InModuleBody {
val clock_wire = Wire(Input(new ClockWithFreq(100)))
val reset_wire = Wire(Input(AsyncReset()))
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey))
slowClockSource.out.unzip._1.map { o =>
o.clock := clock_wire.clock
o.reset := reset_wire
}
// For a real chip you should replace this ClockSourceAtFreqFromPlusArg
// with a blackbox of whatever PLL is being integrated
val fake_pll = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz"))
fake_pll.io.power := pllCtrlSink.in(0)._1.power
fake_pll.io.gate := pllCtrlSink.in(0)._1.gate
pllClockSource.out.unzip._1.map { o =>
o.clock := fake_pll.io.clk
o.reset := reset_wire
}
(Seq(clock_io, reset_io), clockIOCell ++ resetIOCell)
}
}
})
// This passes all clocks through to the TestHarness
class WithPassthroughClockGenerator extends OverrideLazyIOBinder({
(system: HasChipyardPRCI) => {
// Connect the implicit clock
implicit val p = GetSystemParameters(system)
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
system.connectImplicitClockSinkNode(implicitClockSinkNode)
InModuleBody {
val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset
system.asInstanceOf[BaseSubsystem].module match { case l: LazyModuleImp => {
l.clock := implicit_clock
l.reset := implicit_reset
}}
}
// This aggregate node should do nothing
val clockGroupAggNode = ClockGroupAggregateNode("fake")
val clockGroupsSourceNode = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
system.allClockGroupsNode := clockGroupAggNode := clockGroupsSourceNode
InModuleBody {
val reset_io = IO(Input(AsyncReset()))
require(clockGroupAggNode.out.size == 1)
val (bundle, edge) = clockGroupAggNode.out(0)
val clock_ios = (bundle.member.data zip edge.sink.members).map { case (b, m) =>
val freq = m.take.get.freqMHz
val clock_io = IO(Input(new ClockWithFreq(freq))).suggestName(s"clock_${m.name.get}")
b.clock := clock_io.clock
b.reset := reset_io
clock_io
}.toSeq
((clock_ios :+ reset_io), Nil)
}
}
})

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import chisel3.experimental.{Analog, IO}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._

View File

@@ -2,7 +2,7 @@ package chipyard.clocking
import chisel3._
import freechips.rocketchip.config.{Parameters, Config, Field}
import org.chipsalliance.cde.config.{Parameters, Config, Field}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._

View File

@@ -2,7 +2,7 @@ package chipyard.clocking
import chisel3._
import freechips.rocketchip.config.{Parameters}
import org.chipsalliance.cde.config.{Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
import freechips.rocketchip.util.ElaborationArtefacts
@@ -92,57 +92,3 @@ class SimplePllConfiguration(
def referenceSinkParams(): ClockSinkParameters = sinkDividerMap.find(_._2 == 1).get._1
}
case class DividerOnlyClockGeneratorNode(pllName: String)(implicit valName: ValName)
extends MixedNexusNode(ClockImp, ClockGroupImp)(
dFn = { _ => ClockGroupSourceParameters() },
uFn = { u =>
require(u.size == 1)
require(!u.head.members.contains(None),
"All output clocks in group must set their take parameters. Use a ClockGroupDealiaser")
ClockSinkParameters(
name = Some(s"${pllName}_reference_input"),
take = Some(ClockParameters(new SimplePllConfiguration(pllName, u.head.members).referenceFreqMHz))) }
)
/**
* Generates a digital-divider-only PLL model that verilator can simulate.
* Inspects all take-specified frequencies in the output ClockGroup, calculates a
* fast reference clock (roughly LCM(requested frequencies)) which is passed up the
* diplomatic graph, and then generates dividers for each unique requested
* frequency.
*
* Output resets are not synchronized to generated clocks and should be
* synchronized by the user in a manner they see fit.
*
*/
class DividerOnlyClockGenerator(pllName: String)(implicit p: Parameters, valName: ValName) extends LazyModule {
val node = DividerOnlyClockGeneratorNode(pllName)
lazy val module = new Impl
class Impl extends LazyRawModuleImp(this) {
require(node.out.size == 1, "Idealized PLL expects to generate a single output clock group. Use a ClockGroupAggregator")
val (refClock, ClockEdgeParameters(_, refSinkParam, _, _)) = node.in.head
val (outClocks, ClockGroupEdgeParameters(_, outSinkParams, _, _)) = node.out.head
val referenceFreq = refSinkParam.take.get.freqMHz
val pllConfig = new SimplePllConfiguration(pllName, outSinkParams.members)
pllConfig.emitSummaries()
val dividedClocks = mutable.HashMap[Int, Clock]()
def instantiateDivider(div: Int): Clock = {
val divider = Module(new ClockDividerN(div))
divider.suggestName(s"ClockDivideBy${div}")
divider.io.clk_in := refClock.clock
dividedClocks(div) = divider.io.clk_out
divider.io.clk_out
}
for (((sinkBName, sinkB), sinkP) <- outClocks.member.elements.zip(outSinkParams.members)) {
val div = pllConfig.sinkDividerMap(sinkP)
sinkB.clock := dividedClocks.getOrElse(div, instantiateDivider(div))
// Reset handling and synchronization is expected to be handled by a downstream node
sinkB.reset := refClock.reset
}
}
}

View File

@@ -0,0 +1,36 @@
package chipyard.clocking
import chisel3._
import chisel3.util._
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.util._
class FakePLLCtrlBundle extends Bundle {
val gate = Bool()
val power = Bool()
}
class FakePLLCtrl(address: BigInt, beatBytes: Int)(implicit p: Parameters) extends LazyModule
{
val device = new SimpleDevice(s"pll", Nil)
val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes)
val ctrlNode = BundleBridgeSource(() => Output(new FakePLLCtrlBundle))
lazy val module = new LazyModuleImp(this) {
// This PLL only has 2 address, the gate and power
// Both should be set to turn on the PLL
// TODO: Should these be reset by the top level reset pin?
val gate_reg = Module(new AsyncResetRegVec(w=1, init=0))
val power_reg = Module(new AsyncResetRegVec(w=1, init=0))
ctrlNode.out(0)._1.gate := gate_reg.io.q
ctrlNode.out(0)._1.power := power_reg.io.q
tlNode.regmap(
0 -> Seq(RegField.rwReg(1, gate_reg.io)),
4 -> Seq(RegField.rwReg(1, power_reg.io))
)
}
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import scala.collection.mutable.{ArrayBuffer}
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
@@ -15,12 +15,13 @@ import freechips.rocketchip.tile._
import freechips.rocketchip.prci._
import testchipip.{TLTileResetCtrl}
import chipyard.{DefaultClockFrequencyKey}
import chipyard.harness.{DefaultClockFrequencyKey}
case class ChipyardPRCIControlParams(
slaveWhere: TLBusWrapperLocation = CBUS,
baseAddress: BigInt = 0x100000,
enableTileClockGating: Boolean = true
enableTileClockGating: Boolean = true,
enableTileResetSetting: Boolean = true
)
@@ -72,12 +73,13 @@ trait HasChipyardPRCI { this: BaseSubsystem with InstantiatesTiles =>
val frequencySpecifier = ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
val clockGroupCombiner = ClockGroupCombiner()
val resetSynchronizer = ClockGroupResetSynchronizer()
val tileClockGater = prci_ctrl_domain {
TileClockGater(prciParams.baseAddress + 0x00000, tlbus, prciParams.enableTileClockGating)
}
val tileResetSetter = prci_ctrl_domain {
val tileClockGater = if (prciParams.enableTileClockGating) { prci_ctrl_domain {
TileClockGater(prciParams.baseAddress + 0x00000, tlbus)
} } else { ClockGroupEphemeralNode() }
val tileResetSetter = if (prciParams.enableTileResetSetting) { prci_ctrl_domain {
TileResetSetter(prciParams.baseAddress + 0x10000, tlbus, tile_prci_domains.map(_.tile_reset_domain.clockNode.portParams(0).name.get), Nil)
}
} } else { ClockGroupEphemeralNode() }
(aggregator
:= frequencySpecifier
:= clockGroupCombiner

View File

@@ -0,0 +1,56 @@
package chipyard.clocking
import chisel3._
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.util._
import freechips.rocketchip.prci._
import freechips.rocketchip.util.ElaborationArtefacts
import testchipip._
// This module adds a TileLink memory-mapped clock divider to the clock graph
// The output clock/reset pairs from this module should be synchronized later
class TLClockDivider(address: BigInt, beatBytes: Int, divBits: Int = 8)(implicit p: Parameters) extends LazyModule {
val device = new SimpleDevice(s"clk-div-ctrl", Nil)
val clockNode = ClockGroupIdentityNode()
val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes)
lazy val module = new LazyModuleImp(this) {
require (clockNode.out.size == 1)
val sources = clockNode.in.head._1.member.data.toSeq
val sinks = clockNode.out.head._1.member.elements.toSeq
require (sources.size == sinks.size)
val nSinks = sinks.size
val regs = (0 until nSinks) .map { i =>
val sinkName = sinks(i)._1
val asyncReset = sources(i).reset
val reg = withReset (asyncReset) {
Module(new AsyncResetRegVec(w=divBits, init=0))
}
println(s"${(address+i*4).toString(16)}: Clock domain $sinkName divider")
sinks(i)._2.clock := withClockAndReset(sources(i).clock, asyncReset) {
val divider = Module(new testchipip.ClockDivideOrPass(divBits, depth = 3, genClockGate = p(ClockGateImpl)))
divider.io.divisor := reg.io.q
divider.io.resetAsync := ResetStretcher(sources(i).clock, asyncReset, 20).asAsyncReset
divider.io.clockOut
}
// Note this is not synchronized to the output clock, which takes time to appear
// so this is still asyncreset
// Stretch the reset for 40 cycles, to give enough time to reset any downstream
// digital logic
sinks(i)._2.reset := ResetStretcher(sources(i).clock, asyncReset, 40).asAsyncReset
reg
}
tlNode.regmap((0 until nSinks).map { i =>
i * 4 -> Seq(RegField.rwReg(divBits, regs(i).io))
}: _*)
}
}

View File

@@ -0,0 +1,73 @@
package chipyard.clocking
import chisel3._
import chisel3.util._
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.util._
import freechips.rocketchip.prci._
import freechips.rocketchip.util.ElaborationArtefacts
import testchipip._
object ResetStretcher {
def apply(clock: Clock, reset: Reset, cycles: Int): Reset = {
withClockAndReset(clock, reset) {
val n = log2Ceil(cycles)
val count = Module(new AsyncResetRegVec(w=n, init=0))
val resetout = Module(new AsyncResetRegVec(w=1, init=1))
count.io.en := resetout.io.q
count.io.d := count.io.q + 1.U
resetout.io.en := resetout.io.q
resetout.io.d := count.io.q < (cycles-1).U
resetout.io.q.asBool
}
}
}
case class ClockSelNode()(implicit valName: ValName)
extends MixedNexusNode(ClockImp, ClockGroupImp)(
dFn = { d => ClockGroupSourceParameters() },
uFn = { u => ClockSinkParameters() }
)
// This module adds a TileLink memory-mapped clock mux for each downstream clock domain
// in the clock graph. The output clock/reset should be synchronized downstream
class TLClockSelector(address: BigInt, beatBytes: Int)(implicit p: Parameters) extends LazyModule {
val device = new SimpleDevice("clk-sel-ctrl", Nil)
val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes)
val clockNode = ClockSelNode()
lazy val module = new LazyModuleImp(this) {
val asyncReset = clockNode.in.map(_._1).map(_.reset).toSeq(0)
val clocks = clockNode.in.map(_._1).map(_.clock)
val (outClocks, _) = clockNode.out.head
val (sinkNames, sinks) = outClocks.member.elements.toSeq.unzip
val regs = (0 until sinks.size).map { i =>
val sinkName = sinkNames(i)
val sel = Wire(UInt(log2Ceil(clocks.size).W))
val reg = withReset(asyncReset) { Module(new AsyncResetRegVec(w=log2Ceil(clocks.size), init=0)) }
sel := reg.io.q
println(s"${(address+i*4).toString(16)}: Clock domain $sinkName clock mux")
val mux = testchipip.ClockMutexMux(clocks).suggestName(s"${sinkName}_clkmux")
mux.io.sel := sel
mux.io.resetAsync := asyncReset.asAsyncReset
sinks(i).clock := mux.io.clockOut
// Stretch the reset for 20 cycles, to give time to reset any downstream digital logic
sinks(i).reset := ResetStretcher(clocks(0), asyncReset, 20).asAsyncReset
reg
}
tlNode.regmap((0 until sinks.size).map { i =>
i * 4 -> Seq(RegField.rwReg(log2Ceil(clocks.size), regs(i).io))
}: _*)
}
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import chisel3.experimental.{Analog, IO}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
@@ -19,7 +19,7 @@ import freechips.rocketchip.subsystem._
* flag will generate the registers, preserving the same memory map and behavior, but will not
* generate any gaters
*/
class TileClockGater(address: BigInt, beatBytes: Int, enable: Boolean)(implicit p: Parameters, valName: ValName) extends LazyModule
class TileClockGater(address: BigInt, beatBytes: Int)(implicit p: Parameters, valName: ValName) extends LazyModule
{
val device = new SimpleDevice(s"clock-gater", Nil)
val clockNode = ClockGroupIdentityNode()
@@ -31,8 +31,8 @@ class TileClockGater(address: BigInt, beatBytes: Int, enable: Boolean)(implicit
val regs = (0 until nSinks).map({i =>
val sinkName = sinks(i)._1
val reg = withReset(sources(i).reset) { Module(new AsyncResetRegVec(w=1, init=1)) }
if (sinkName.contains("tile") && enable) {
println(s"ClockGate for ${sinkName} regmapped at ${(address+i*4).toString(16)}")
if (sinkName.contains("tile")) {
println(s"${(address+i*4).toString(16)}: Tile $sinkName clock gate")
sinks(i)._2.clock := ClockGate(sources(i).clock, reg.io.q.asBool)
sinks(i)._2.reset := sources(i).reset
} else {
@@ -47,8 +47,8 @@ class TileClockGater(address: BigInt, beatBytes: Int, enable: Boolean)(implicit
}
object TileClockGater {
def apply(address: BigInt, tlbus: TLBusWrapper, enable: Boolean)(implicit p: Parameters, v: ValName) = {
val gater = LazyModule(new TileClockGater(address, tlbus.beatBytes, enable))
def apply(address: BigInt, tlbus: TLBusWrapper)(implicit p: Parameters, v: ValName) = {
val gater = LazyModule(new TileClockGater(address, tlbus.beatBytes))
tlbus.toVariableWidthSlave(Some("clock-gater")) { gater.tlNode := TLBuffer() }
gater.clockNode
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import chisel3.experimental.{Analog, IO}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
@@ -39,16 +39,16 @@ class TileResetSetter(address: BigInt, beatBytes: Int, tileNames: Seq[String], i
}): _*)
val tileMap = tileNames.zipWithIndex.map({ case (n, i) =>
n -> (tile_async_resets(i), r_tile_resets(i).io.q)
n -> (tile_async_resets(i), r_tile_resets(i).io.q, address + i * 4)
})
(clockNode.out zip clockNode.in).map { case ((o, _), (i, _)) =>
(o.member.elements zip i.member.elements).foreach { case ((name, oD), (_, iD)) =>
oD.clock := iD.clock
oD.reset := iD.reset
for ((n, (rIn, rOut)) <- tileMap) {
for ((n, (rIn, rOut, addr)) <- tileMap) {
if (name.contains(n)) {
println(name, n)
println(s"${addr.toString(16)}: Tile $name reset control")
// Async because the reset coming out of the AsyncResetRegVec is
// clocked to the bus this is attached to, not the clock in this
// clock bundle. We expect a ClockGroupResetSynchronizer downstream

View File

@@ -1,6 +1,6 @@
package chipyard.config
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// --------------
// Chipyard abstract ("base") configuration
@@ -12,17 +12,18 @@ import freechips.rocketchip.config.{Config}
class AbstractConfig extends Config(
// The HarnessBinders control generation of hardware in the TestHarness
new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present
new chipyard.harness.WithBlackBoxSimMem ++ // add SimDRAM DRAM model for axi4 backing memory, if axi4 mem is enabled
new chipyard.harness.WithSimSerial ++ // add external serial-adapter and RAM
new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled
new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are present
new chipyard.harness.WithSimSPIFlashModel ++ // add simulated SPI flash memory, if SPI is enabled
new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled
new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present
new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present
new chipyard.harness.WithCustomBootPinPlusArg ++
new chipyard.harness.WithClockAndResetFromHarness ++
new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present
new chipyard.harness.WithBlackBoxSimMem ++ // add SimDRAM DRAM model for axi4 backing memory, if axi4 mem is enabled
new chipyard.harness.WithSimTSIOverSerialTL ++ // add external serial-adapter and RAM
new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled
new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are present
new chipyard.harness.WithSimSPIFlashModel ++ // add simulated SPI flash memory, if SPI is enabled
new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled
new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present
new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present
new chipyard.harness.WithCustomBootPinPlusArg ++ // drive custom-boot pin with a plusarg, if custom-boot-pin is present
new chipyard.harness.WithClockAndResetFromHarness ++ // all Clock/Reset I/O in ChipTop should be driven by harnessClockInstantiator
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // generate clocks in harness with unsynthesizable ClockSourceAtFreqMHz
// The IOBinders instantiate ChipTop IOs to match desired digital IOs
// IOCells are generated for "Chip-like" IOs, while simulation-only IOs are directly punched through
@@ -40,18 +41,24 @@ class AbstractConfig extends Config(
new chipyard.iobinders.WithTraceIOPunchthrough ++
new chipyard.iobinders.WithExtInterruptIOCells ++
new chipyard.iobinders.WithCustomBootPin ++
new chipyard.iobinders.WithDividerOnlyClockGenerator ++
// By default, punch out IOs to the Harness
new chipyard.clocking.WithPassthroughClockGenerator ++
new testchipip.WithCustomBootPin ++ // add a custom-boot-pin to support pin-driven boot address
new testchipip.WithBootAddrReg ++ // add a boot-addr-reg for configurable boot address
new testchipip.WithSerialTLWidth(32) ++ // fatten the serialTL interface to improve testing performance
new testchipip.WithDefaultSerialTL ++ // use serialized tilelink port to external serialadapter/harnessRAM
new chipyard.config.WithDebugModuleAbstractDataWords(8) ++ // increase debug module data capacity
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 chipyard.config.WithInheritBusFrequencyAssignments ++ // Unspecified clocks within a bus will receive the bus frequency if set
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // Unspecified frequencies with match the pbus frequency (which is always set)
new chipyard.config.WithMemoryBusFrequency(100.0) ++ // Default 100 MHz mbus
new chipyard.config.WithPeripheryBusFrequency(100.0) ++ // Default 100 MHz pbus
new chipyard.config.WithMemoryBusFrequency(500.0) ++ // Default 500 MHz mbus
new chipyard.config.WithPeripheryBusFrequency(500.0) ++ // Default 500 MHz pbus
new freechips.rocketchip.subsystem.WithNMemoryChannels(2) ++ // Default 2 memory channels
new freechips.rocketchip.subsystem.WithClockGateModel ++ // add default EICG_wrapper clock gate model
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)
@@ -60,4 +67,5 @@ class AbstractConfig extends Config(
new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts
new freechips.rocketchip.subsystem.WithDontDriveBusClocksFromSBus ++ // leave the bus clocks undriven by sbus
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ // hierarchical buses including sbus/mbus/pbus/fbus/cbus/l2
new freechips.rocketchip.subsystem.WithDTS("ucb-bar,chipyard", Nil) ++ // custom device name for DTS
new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// ---------------------
// BOOM Configs
@@ -53,3 +53,18 @@ class MediumBoomCosimConfig extends Config(
new chipyard.config.WithTraceIO ++ // enable the traceio
new boom.common.WithNMediumBooms(1) ++
new chipyard.config.AbstractConfig)
class dmiMediumBoomConfig extends Config(
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anything to serial-tl
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new boom.common.WithNMediumBooms(1) ++
new chipyard.config.AbstractConfig)
class dmiMediumBoomCosimConfig extends Config(
new chipyard.harness.WithCospike ++ // attach spike-cosim
new chipyard.config.WithTraceIO ++ // enable the traceio
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anythint to serial-tl
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new boom.common.WithNMediumBooms(1) ++
new chipyard.config.AbstractConfig)

View File

@@ -2,7 +2,7 @@ package chipyard
import chisel3._
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// ---------------------
// CVA6 Configs
@@ -13,7 +13,7 @@ class CVA6Config extends Config(
new chipyard.config.AbstractConfig)
class dmiCVA6Config extends Config(
new chipyard.harness.WithSerialAdapterTiedOff ++ // Tie off the serial port, override default instantiation of SimSerial
new chipyard.harness.WithSerialTLTiedOff ++ // Tie off the serial-tilelink port
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new cva6.WithNCVA6Cores(1) ++ // single CVA6 core
new chipyard.config.AbstractConfig)

View File

@@ -0,0 +1,38 @@
package chipyard
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy._
// A simple config demonstrating how to set up a basic chip in Chipyard
class ChipLikeQuadRocketConfig extends Config(
//==================================
// Set up TestHarness
//==================================
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // use absolute frequencies for simulations in the harness
// NOTE: This only simulates properly in VCS
//==================================
// Set up tiles
//==================================
new freechips.rocketchip.subsystem.WithAsynchronousRocketTiles(3, 3) ++ // Add rational crossings between RocketTile and uncore
new freechips.rocketchip.subsystem.WithNBigCores(4) ++ // quad-core (4 RocketTiles)
//==================================
// Set up I/O
//==================================
new testchipip.WithSerialTLWidth(4) ++
new chipyard.harness.WithSimAXIMemOverSerialTL ++ // Attach fast SimDRAM to TestHarness
new chipyard.config.WithSerialTLBackingMemory ++ // Backing memory is over serial TL protocol
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 4L) ++ // 4GB max external memory
new freechips.rocketchip.subsystem.WithNMemoryChannels(1) ++ // 1 memory channel
//==================================
// Set up clock./reset
//==================================
new chipyard.clocking.WithPLLSelectorDividerClockGenerator ++ // Use a PLL-based clock selector/divider generator structure
// Create the uncore clock group
new chipyard.clocking.WithClockGroupsCombinedByName("uncore", "implicit", "sbus", "mbus", "cbus", "system_bus", "fbus", "pbus") ++
new chipyard.config.AbstractConfig)

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// ---------------------
// Heterogenous Configs

View File

@@ -2,7 +2,7 @@ package chipyard
import chisel3._
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// ---------------------
// Ibex Configs

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// ------------------------------
@@ -9,6 +9,7 @@ import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// DOC include start: FFTRocketConfig
class FFTRocketConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO: hack around dontTouch not working in SFC
new fftgenerator.WithFFTGenerator(numPoints=8, width=16, decPt=8) ++ // add 8-point mmio fft at the default addr (0x2400) with 16bit fixed-point numbers.
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)
@@ -58,6 +59,7 @@ class LargeNVDLARocketConfig extends Config(
new chipyard.config.AbstractConfig)
class ManyMMIOAcceleratorRocketConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO: hack around dontTouch not working in SFC
new fftgenerator.WithFFTGenerator(numPoints=8, width=16, decPt=8) ++ // add 8-point mmio fft at the default addr (0x2400) with 16bit fixed-point numbers.
new nvidia.blocks.dla.WithNVDLA("small") ++ // add a small NVDLA
new chipyard.example.WithStreamingPassthrough ++ // use top with tilelink-controlled streaming passthrough

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
import freechips.rocketchip.subsystem.{SBUS, MBUS}

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// A empty config with no cores. Useful for testing
class NoCoresConfig extends Config(

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// ---------------------------------------------------------
@@ -58,7 +58,7 @@ class LBWIFRocketConfig extends Config(
// DOC include start: DmiRocket
class dmiRocketConfig extends Config(
new chipyard.harness.WithSerialAdapterTiedOff ++ // don't attach an external SimSerial
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anything to serial-tl
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// ------------------------------

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// --------------
@@ -12,6 +12,7 @@ class RocketConfig extends Config(
new chipyard.config.AbstractConfig)
class TinyRocketConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO FIX: Don't dontTouch the ports
new chipyard.config.WithTLSerialLocation(
freechips.rocketchip.subsystem.FBUS,
freechips.rocketchip.subsystem.PBUS) ++ // attach TL serial adapter to f/p busses
@@ -85,6 +86,7 @@ class MbusScratchpadRocketConfig extends Config(
// DOC include end: mbusscratchpadrocket
class MulticlockRocketConfig extends Config(
new freechips.rocketchip.subsystem.WithAsynchronousRocketTiles(3, 3) ++ // Add async crossings between RocketTile and uncore
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
// Frequency specifications
new chipyard.config.WithTileFrequency(1600.0) ++ // Matches the maximum frequency of U540
@@ -95,7 +97,6 @@ class MulticlockRocketConfig extends Config(
// Crossing specifications
new chipyard.config.WithCbusToPbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between PBUS and CBUS
new chipyard.config.WithSbusToMbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossings between backside of L2 and MBUS
new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore
new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS
new chipyard.config.AbstractConfig)
@@ -124,5 +125,12 @@ class MulticlockAXIOverSerialConfig extends Config(
new chipyard.config.WithSerialTLBackingMemory ++ // remove axi4 mem port in favor of SerialTL memory
new freechips.rocketchip.subsystem.WithNBigCores(2) ++
new freechips.rocketchip.subsystem.WithNMemoryChannels(1) ++ // 1 memory channel
new chipyard.config.AbstractConfig)
// DOC include end: MulticlockAXIOverSerialConfig
class CustomIOChipTopRocketConfig extends Config(
new chipyard.example.WithCustomChipTop ++
new chipyard.example.WithCustomIOCells ++
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core
new chipyard.config.AbstractConfig)

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// --------------

View File

@@ -2,7 +2,7 @@ package chipyard
import chisel3._
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
class Sodor1StageConfig extends Config(
// Create a Sodor 1-stage core

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// Configs which instantiate a Spike-simulated
// tile that interacts with the Chipyard SoC
@@ -10,10 +10,47 @@ class SpikeConfig extends Config(
new chipyard.WithNSpikeCores(1) ++
new chipyard.config.AbstractConfig)
class dmiSpikeConfig extends Config(
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anything to serial-tilelink
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new SpikeConfig)
// Avoids polling on the UART registers
class SpikeFastUARTConfig extends Config(
new chipyard.WithNSpikeCores(1) ++
new chipyard.config.WithUARTFIFOEntries(128, 128) ++
new chipyard.config.WithMemoryBusFrequency(1) ++
new chipyard.config.WithPeripheryBusFrequency(1) ++
new chipyard.config.WithMemoryBusFrequency(2) ++
new chipyard.config.WithPeripheryBusFrequency(2) ++
new chipyard.config.AbstractConfig)
// Makes the UART fast, also builds no L2 and a ludicrous L1D
class SpikeUltraFastConfig extends Config(
new chipyard.WithSpikeTCM ++
new chipyard.WithNSpikeCores(1) ++
new testchipip.WithSerialPBusMem ++
new chipyard.config.WithUARTFIFOEntries(128, 128) ++
new chipyard.config.WithMemoryBusFrequency(2) ++
new chipyard.config.WithPeripheryBusFrequency(2) ++
new chipyard.config.WithBroadcastManager ++
new chipyard.config.AbstractConfig)
class dmiSpikeUltraFastConfig extends Config(
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anything to serial-tilelink
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new SpikeUltraFastConfig)
// Add the default firechip devices
class SpikeUltraFastDevicesConfig extends Config(
new chipyard.harness.WithSimBlockDevice ++
new chipyard.harness.WithLoopbackNIC ++
new icenet.WithIceNIC ++
new testchipip.WithBlockDevice ++
new chipyard.WithSpikeTCM ++
new chipyard.WithNSpikeCores(1) ++
new testchipip.WithSerialPBusMem ++
new chipyard.config.WithUARTFIFOEntries(128, 128) ++
new chipyard.config.WithMemoryBusFrequency(2) ++
new chipyard.config.WithPeripheryBusFrequency(2) ++
new chipyard.config.WithBroadcastManager ++
new chipyard.config.AbstractConfig)

View File

@@ -1,15 +1,16 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.rocket.{DCacheParams}
class AbstractTraceGenConfig extends Config(
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++
new chipyard.harness.WithBlackBoxSimMem ++
new chipyard.harness.WithTraceGenSuccess ++
new chipyard.harness.WithClockAndResetFromHarness ++
new chipyard.iobinders.WithAXI4MemPunchthrough ++
new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++
new chipyard.iobinders.WithDividerOnlyClockGenerator ++
new chipyard.clocking.WithPassthroughClockGenerator ++
new chipyard.config.WithTracegenSystem ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import constellation.channel._
import constellation.routing._
import constellation.topology._
@@ -77,6 +77,7 @@ class TutorialSha3BlackBoxConfig extends Config(
// Tutorial Phase 5: Map a multicore heterogeneous SoC with multiple cores and memory-mapped accelerators
class TutorialNoCConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++
// Try changing the dimensions of the Mesh topology
new constellation.soc.WithGlobalNoC(constellation.soc.GlobalNoCParams(
NoCParams(

View File

@@ -4,7 +4,7 @@ import scala.util.matching.Regex
import chisel3._
import chisel3.util.{log2Up}
import freechips.rocketchip.config.{Field, Parameters, Config}
import org.chipsalliance.cde.config.{Field, Parameters, Config}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.prci._
import freechips.rocketchip.diplomacy._
@@ -13,7 +13,7 @@ import freechips.rocketchip.tilelink.{HasTLBusParams}
import chipyard._
import chipyard.clocking._
import chipyard.harness.{DefaultClockFrequencyKey}
// The default RocketChip BaseSubsystem drives its diplomatic clock graph
// with the implicit clocks of Subsystem. Don't do that, instead we extend

View File

@@ -4,7 +4,7 @@ import scala.util.matching.Regex
import chisel3._
import chisel3.util.{log2Up}
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.devices.tilelink.{BootROMLocated, PLICKey}
import freechips.rocketchip.devices.debug.{Debug, ExportDebug, DebugModuleKey, DMI}
import freechips.rocketchip.stage.phases.TargetDirKey
@@ -87,3 +87,7 @@ class WithExtMemIdBits(n: Int) extends Config((site, here, up) => {
class WithNoPLIC extends Config((site, here, up) => {
case PLICKey => None
})
class WithDebugModuleAbstractDataWords(words: Int = 16) extends Config((site, here, up) => {
case DebugModuleKey => up(DebugModuleKey).map(_.copy(nAbstractDataWords=words))
})

View File

@@ -2,7 +2,7 @@ package chipyard.config
import chisel3._
import freechips.rocketchip.config.{Field, Parameters, Config}
import org.chipsalliance.cde.config.{Field, Parameters, Config}
import freechips.rocketchip.tile._
import freechips.rocketchip.diplomacy._

View File

@@ -1,6 +1,6 @@
package chipyard.config
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.subsystem.{SystemBusKey, BankedL2Key, CoherenceManagerWrapper}
import freechips.rocketchip.diplomacy.{DTSTimebase}

Some files were not shown because too many files have changed in this diff Show More