From b934c51315cef30c899c8ffe2a4d7c73acce5920 Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Thu, 24 Oct 2019 10:26:45 -0700 Subject: [PATCH 01/75] Add phony firrtl target to just build firrtl file (#317) --- common.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common.mk b/common.mk index 317f2678..95d7c614 100644 --- a/common.mk +++ b/common.mk @@ -43,6 +43,9 @@ $(FIRRTL_FILE) $(ANNO_FILE): generator_temp generator_temp: $(SCALA_SOURCES) $(sim_files) mkdir -p $(build_dir) cd $(base_dir) && $(SBT) "project $(SBT_PROJECT)" "runMain $(GENERATOR_PACKAGE).Generator $(build_dir) $(MODEL_PACKAGE) $(MODEL) $(CONFIG_PACKAGE) $(CONFIG)" + +.PHONY: firrtl +firrtl: $(FIRRTL_FILE) ######################################################################################### # create verilog files rules and variables From 540fff55e2267df75f891c8f20cbec7bb70f72c4 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Fri, 25 Oct 2019 09:47:22 -0700 Subject: [PATCH 02/75] Fix VLSI Makefile [skip ci] The `SMEMS_FILE` was supposed to be `TOP_SMEMS_FILE` --- vlsi/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlsi/Makefile b/vlsi/Makefile index 567090da..675f93b3 100644 --- a/vlsi/Makefile +++ b/vlsi/Makefile @@ -71,7 +71,7 @@ srams: sram_generator sram_generator: $(SRAM_CONF) # This should be built alongside $(SMEMS_FILE) -$(SMEMS_HAMMER): $(SMEMS_FILE) +$(SMEMS_HAMMER): $(TOP_SMEMS_FILE) $(SRAM_GENERATOR_CONF): $(SMEMS_HAMMER) mkdir -p $(dir $@) From 69d3f9d4997946dfc7273e05a9bde3a0a050279e Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Fri, 25 Oct 2019 09:49:20 -0700 Subject: [PATCH 03/75] Update vlsi/Makefile [skip ci] --- vlsi/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlsi/Makefile b/vlsi/Makefile index 675f93b3..bdbeb1bb 100644 --- a/vlsi/Makefile +++ b/vlsi/Makefile @@ -70,7 +70,7 @@ SRAM_CONF=$(build_dir)/sram_generator-output.json srams: sram_generator sram_generator: $(SRAM_CONF) -# This should be built alongside $(SMEMS_FILE) +# This should be built alongside $(TOP_SMEMS_FILE) $(SMEMS_HAMMER): $(TOP_SMEMS_FILE) $(SRAM_GENERATOR_CONF): $(SMEMS_HAMMER) From bd6397130be791fcb6e9fe1cd5880f6879d97911 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 31 Oct 2019 15:54:09 -0700 Subject: [PATCH 04/75] make sure grep filter only omits .h files --- common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.mk b/common.mk index 95d7c614..8581fbb0 100644 --- a/common.mk +++ b/common.mk @@ -80,7 +80,7 @@ harness_macro_temp: $(HARNESS_SMEMS_CONF) # remove duplicate files and headers in list of simulation file inputs ######################################################################################## $(sim_common_files): $(sim_files) $(sim_top_blackboxes) $(sim_harness_blackboxes) - awk '{print $1;}' $^ | sort -u | grep -v '.*\.h' > $@ + awk '{print $1;}' $^ | sort -u | grep -v '.*\.h$$' > $@ ######################################################################################### # helper rule to just make verilog files From 4ce531c5313f01ab33935f8f8779be8f3e1ad3ed Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Tue, 5 Nov 2019 07:04:07 +0000 Subject: [PATCH 05/75] add coremark and spec firemarshal workloads --- .gitmodules | 6 ++++++ software/coremark | 1 + software/spec2017 | 1 + 3 files changed, 8 insertions(+) create mode 160000 software/coremark create mode 160000 software/spec2017 diff --git a/.gitmodules b/.gitmodules index 282dc731..14c593bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -98,3 +98,9 @@ [submodule "tools/axe"] path = tools/axe url = https://github.com/CTSRD-CHERI/axe.git +[submodule "software/spec2017"] + path = software/spec2017 + url = https://github.com/ucb-bar/spec2017-workload.git +[submodule "software/coremark"] + path = software/coremark + url = https://github.com/ucb-bar/coremark-workload.git diff --git a/software/coremark b/software/coremark new file mode 160000 index 00000000..a6cc1cbf --- /dev/null +++ b/software/coremark @@ -0,0 +1 @@ +Subproject commit a6cc1cbfd9d2387c36ac4b415fdd8142951d9bfe diff --git a/software/spec2017 b/software/spec2017 new file mode 160000 index 00000000..f5cbc4aa --- /dev/null +++ b/software/spec2017 @@ -0,0 +1 @@ +Subproject commit f5cbc4aaa536afac383d554df28291a7d27c57be From c8191b95deada51cb9e526ae77f7e5fe2dcb921d Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Tue, 5 Nov 2019 07:06:17 +0000 Subject: [PATCH 06/75] bump firesim --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index da4d8cd9..21475d1c 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit da4d8cd9fdca5e424d0982e93846476011be7372 +Subproject commit 21475d1c90500c01d3eb18a684831be93de6b089 From d54a178f3621365e6894430cd07fd4f366d5d758 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Wed, 6 Nov 2019 11:18:08 -0800 Subject: [PATCH 07/75] partition objdir --- vlsi/Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/vlsi/Makefile b/vlsi/Makefile index bdbeb1bb..4606492f 100644 --- a/vlsi/Makefile +++ b/vlsi/Makefile @@ -28,11 +28,16 @@ ifeq ($(tech_name),asap7) else MACROCOMPILER_MODE ?= -l $(SMEMS_CACHE) -hir $(SMEMS_HAMMER) endif -OBJ_DIR ?= $(vlsi_dir)/build -ENV_YML ?= $(vlsi_dir)/env.yml -INPUT_CONFS ?= example.yml +ENV_YML ?= $(vlsi_dir)/bwrc-env.yml +INPUT_CONFS ?= example.yml $(dir $(tech_dir))/bwrc.yml HAMMER_EXEC ?= ./example-vlsi VLSI_TOP ?= $(TOP) +VLSI_OBJ_DIR ?= $(vlsi_dir)/build +ifneq($(CUSTOM_VLOG), ) + OBJ_DIR ?= $(VLSI_OBJ_DIR)/custom-$(VLSI_TOP) +else + OBJ_DIR ?= $(VLSI_OBJ_DIR)/$(long_name)-$(VLSI_TOP) +endif ######################################################################################### # general rules @@ -119,4 +124,4 @@ $(OBJ_DIR)/hammer.d: $(HAMMER_D_DEPS) ######################################################################################### .PHONY: clean clean: - rm -rf $(OBJ_DIR) hammer-vlsi*.log __pycache__ output.json $(GENERATED_CONFS) $(gen_dir) + rm -rf $(VLSI_OBJ_DIR) hammer-vlsi*.log __pycache__ output.json $(GENERATED_CONFS) $(gen_dir) From abbd9ce9053ff622d7b2810e38708ed6aaa952b3 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Tue, 5 Nov 2019 07:20:54 +0000 Subject: [PATCH 08/75] templates for issues and prs [skip ci] --- .github/ISSUE_TEMPLATE.md | 28 ++++++++++++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 13 +++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..df4daa2e --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,28 @@ + +**Type of issue**: bug report | feature request | question | other enhancement + + + + +**Impact**: no rtl change | rtl refactoring | new rtl | unknown + + +**Development Phase**: request | proposal + +**Other information** + + + + +**What is the current behavior?** + +**What is the expected behavior?** + +**Please tell us about your environment:** + + +**What is the use case for changing the behavior?** diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..fe031ca1 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +**Related issue**: + + +**Type of change**: bug fix | new feature | other enhancement + + +**Impact**: no rtl change | rtl refactoring | new rtl | unknown + + +**Development Phase**: proposal | implementation + +**Release Notes** + From c39ba5713c939ddb50e916971bc999b7256d89c9 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Wed, 6 Nov 2019 13:38:41 -0800 Subject: [PATCH 09/75] split issue templates [skip ci] --- .github/ISSUE_TEMPLATE.md | 28 ----------------------- .github/ISSUE_TEMPLATE/bug-report.md | 23 +++++++++++++++++++ .github/ISSUE_TEMPLATE/feature-request.md | 11 +++++++++ .github/ISSUE_TEMPLATE/other.md | 6 +++++ .github/ISSUE_TEMPLATE/question.md | 13 +++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 5 +--- 6 files changed, 54 insertions(+), 32 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/bug-report.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request.md create mode 100644 .github/ISSUE_TEMPLATE/other.md create mode 100644 .github/ISSUE_TEMPLATE/question.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index df4daa2e..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,28 +0,0 @@ - -**Type of issue**: bug report | feature request | question | other enhancement - - - - -**Impact**: no rtl change | rtl refactoring | new rtl | unknown - - -**Development Phase**: request | proposal - -**Other information** - - - - -**What is the current behavior?** - -**What is the expected behavior?** - -**Please tell us about your environment:** - - -**What is the use case for changing the behavior?** diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 00000000..4da4667e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,23 @@ +--- +name: Bug Report +about: Report a problem with Chipyard +labels: bug + +--- + + +**Impact**: rtl | software | unknown | other + +**What is the current behavior?** + +**What is the expected behavior?** + +**Please tell us about your environment:** + + +**Other information** + diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 00000000..66e68155 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,11 @@ +--- +name: Feature Request +about: Propose a change to Chipyard + +--- + + +**Impact**: rtl | software | unknown | other + +**Description** + diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md new file mode 100644 index 00000000..b41a5e5c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/other.md @@ -0,0 +1,6 @@ +--- +name: Other +about: Something else! + +--- + diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..b8c3f482 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,13 @@ +--- +name: Question +about: Ask a question +labels: question + +--- + + + + + + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fe031ca1..4949e777 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,10 +4,7 @@ **Type of change**: bug fix | new feature | other enhancement -**Impact**: no rtl change | rtl refactoring | new rtl | unknown - - -**Development Phase**: proposal | implementation +**Impact**: rtl change | software change | unknown | other **Release Notes** From 8439f1d5e18a9b798f62c3f84807ad39eeda7f15 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Wed, 6 Nov 2019 13:42:03 -0800 Subject: [PATCH 10/75] re-add motivating example to feature request issue [skip ci] --- .github/ISSUE_TEMPLATE/feature-request.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 66e68155..70e2081d 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -9,3 +9,5 @@ about: Propose a change to Chipyard **Description** + +**What is a motivating example for changing the behavior?** From 443be014958fa8066dba1f64f923abd90c56726b Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Wed, 6 Nov 2019 13:48:24 -0800 Subject: [PATCH 11/75] remove notion of bwrc-env and remove from INPUT_CONFS [skip ci] --- sims/firesim | 2 +- vlsi/Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sims/firesim b/sims/firesim index 21475d1c..afad1b6a 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 21475d1c90500c01d3eb18a684831be93de6b089 +Subproject commit afad1b6accfaba5efbc0cfeea66372abae5ab2eb diff --git a/vlsi/Makefile b/vlsi/Makefile index 4606492f..d7135bb5 100644 --- a/vlsi/Makefile +++ b/vlsi/Makefile @@ -28,8 +28,8 @@ ifeq ($(tech_name),asap7) else MACROCOMPILER_MODE ?= -l $(SMEMS_CACHE) -hir $(SMEMS_HAMMER) endif -ENV_YML ?= $(vlsi_dir)/bwrc-env.yml -INPUT_CONFS ?= example.yml $(dir $(tech_dir))/bwrc.yml +ENV_YML ?= $(vlsi_dir)/env.yml +INPUT_CONFS ?= example.yml HAMMER_EXEC ?= ./example-vlsi VLSI_TOP ?= $(TOP) VLSI_OBJ_DIR ?= $(vlsi_dir)/build From d9b6b86b462729dc99a380573977e716c8b1d308 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Thu, 7 Nov 2019 13:43:59 -0800 Subject: [PATCH 12/75] bump barstools --- tools/barstools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/barstools b/tools/barstools index 26096e07..3bba55cc 160000 --- a/tools/barstools +++ b/tools/barstools @@ -1 +1 @@ -Subproject commit 26096e07f6ce3e12b2114132c2859ef56fb0cfaf +Subproject commit 3bba55ccc89518ddeb3ed78774dd6e68d938c07a From 542b165fd61a96779b8e8c09aa1dc10a4ef3c7dd Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Mon, 11 Nov 2019 11:13:14 -0800 Subject: [PATCH 13/75] cleanup build script for ci | bump firesim --- .circleci/do-firesim-build.sh | 1 - sims/firesim | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.circleci/do-firesim-build.sh b/.circleci/do-firesim-build.sh index ecb965b2..5eb42e56 100755 --- a/.circleci/do-firesim-build.sh +++ b/.circleci/do-firesim-build.sh @@ -15,7 +15,6 @@ trap clean EXIT cd $LOCAL_CHIPYARD_DIR ./scripts/init-submodules-no-riscv-tools.sh -cd sims/firesim/sim/midas && git submodule update --init # set stricthostkeychecking to no (must happen before rsync) run "echo \"Ping $SERVER\"" diff --git a/sims/firesim b/sims/firesim index afad1b6a..9d807922 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit afad1b6accfaba5efbc0cfeea66372abae5ab2eb +Subproject commit 9d80792262eb3f15e20bc6f7f4016cb049efefda From 77deedbfb8edcc28a114d5678a5ba35dab0c1fc6 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Mon, 11 Nov 2019 15:04:16 -0800 Subject: [PATCH 14/75] bump firesim for midaexamples fix --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index 9d807922..c3a4731a 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 9d80792262eb3f15e20bc6f7f4016cb049efefda +Subproject commit c3a4731a604973d7b2b420a308116e9e3e093dc3 From 6ca1715b47a315777f2c11a33035f03c0af32309 Mon Sep 17 00:00:00 2001 From: Nathan Pemberton Date: Tue, 12 Nov 2019 17:18:02 -0500 Subject: [PATCH 15/75] Bump firemarshal to not initialize linux by default. This bumps the sha3 generator to include the software workloads (moved from marshal). As a result, the sha3 generator submodule is not initialized by default (because it now has a copy of linux). --- generators/sha3 | 2 +- scripts/init-submodules-no-riscv-tools.sh | 5 +++++ sims/firesim | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/generators/sha3 b/generators/sha3 index 60ddfe7c..e3ff7593 160000 --- a/generators/sha3 +++ b/generators/sha3 @@ -1 +1 @@ -Subproject commit 60ddfe7c5b2c1640d91e7d9a35c65011c1600810 +Subproject commit e3ff75939d7f234a626eea641598e223f83ecb19 diff --git a/scripts/init-submodules-no-riscv-tools.sh b/scripts/init-submodules-no-riscv-tools.sh index d8842050..faa78bb6 100755 --- a/scripts/init-submodules-no-riscv-tools.sh +++ b/scripts/init-submodules-no-riscv-tools.sh @@ -32,6 +32,9 @@ for name in toolchains/*/*/ ; do done git config submodule.toolchains/qemu.update none +# Don't automatically initialize generators with big submodules (e.g. linux source) +git config submodule.generators/sha3.update none + # Disable updates to the FireSim submodule until explicitly requested git config submodule.sims/firesim.update none # Disable updates to the hammer tool plugins repos @@ -49,6 +52,8 @@ git config --unset submodule.vlsi/hammer-cadence-plugins.update git config --unset submodule.vlsi/hammer-synopsys-plugins.update git config --unset submodule.vlsi/hammer-mentor-plugins.update +git config --unset submodule.generators/sha3.update + if [ $NO_FIRESIM = false ]; then echo "initializing firesim" # Renable firesim and init only the required submodules to provide diff --git a/sims/firesim b/sims/firesim index afad1b6a..e57b4ede 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit afad1b6accfaba5efbc0cfeea66372abae5ab2eb +Subproject commit e57b4ede73d53d13cc5e7d60138a593f55a64c3b From 6d2f102a7e121f57d09cf30117527c5304c8d733 Mon Sep 17 00:00:00 2001 From: Nathan Pemberton Date: Tue, 12 Nov 2019 19:42:36 -0500 Subject: [PATCH 16/75] Shallow clone sha3 --- generators/sha3 | 2 +- scripts/init-submodules-no-riscv-tools.sh | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/generators/sha3 b/generators/sha3 index e3ff7593..e27d808c 160000 --- a/generators/sha3 +++ b/generators/sha3 @@ -1 +1 @@ -Subproject commit e3ff75939d7f234a626eea641598e223f83ecb19 +Subproject commit e27d808cf1a637a8f2a80fc5dcde44c3d0a41c5c diff --git a/scripts/init-submodules-no-riscv-tools.sh b/scripts/init-submodules-no-riscv-tools.sh index faa78bb6..c61f8b3e 100755 --- a/scripts/init-submodules-no-riscv-tools.sh +++ b/scripts/init-submodules-no-riscv-tools.sh @@ -53,6 +53,8 @@ git config --unset submodule.vlsi/hammer-synopsys-plugins.update git config --unset submodule.vlsi/hammer-mentor-plugins.update git config --unset submodule.generators/sha3.update +# Shallow clone by default (recursive clone would get linux) +git submodule update --init generators/sha3 if [ $NO_FIRESIM = false ]; then echo "initializing firesim" From 06216db269796964c197263b9a0f3383a11b70ec Mon Sep 17 00:00:00 2001 From: Nathan Pemberton Date: Wed, 13 Nov 2019 14:52:31 -0500 Subject: [PATCH 17/75] Bump firesim --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index e57b4ede..71e18b39 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit e57b4ede73d53d13cc5e7d60138a593f55a64c3b +Subproject commit 71e18b39884c42bc6ab4d7b5f918384c3e5890f9 From 126efe7594e8674343bfb83f2f03a4dfb2870887 Mon Sep 17 00:00:00 2001 From: Nathan Pemberton Date: Wed, 13 Nov 2019 19:34:02 -0500 Subject: [PATCH 18/75] Final firesim bump (to dev) --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index 71e18b39..cfeb0e67 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 71e18b39884c42bc6ab4d7b5f918384c3e5890f9 +Subproject commit cfeb0e67fe58f896b95459e110802903fed5145a From 8cf0955cb55de57ad3e89b08eef434ef51974243 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Thu, 14 Nov 2019 15:50:07 -0800 Subject: [PATCH 19/75] update coremark to support baremetal --- software/coremark | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/coremark b/software/coremark index a6cc1cbf..cf8b8f7d 160000 --- a/software/coremark +++ b/software/coremark @@ -1 +1 @@ -Subproject commit a6cc1cbfd9d2387c36ac4b415fdd8142951d9bfe +Subproject commit cf8b8f7d82e085b3ecb31865fa40fb3dd62554f2 From a5988c39639f13cce50826247599d56db07b8105 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 20 Nov 2019 19:44:58 -0800 Subject: [PATCH 20/75] Fix syntax error in vlsi/Makefile --- vlsi/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlsi/Makefile b/vlsi/Makefile index d7135bb5..a41368c5 100644 --- a/vlsi/Makefile +++ b/vlsi/Makefile @@ -33,7 +33,7 @@ INPUT_CONFS ?= example.yml HAMMER_EXEC ?= ./example-vlsi VLSI_TOP ?= $(TOP) VLSI_OBJ_DIR ?= $(vlsi_dir)/build -ifneq($(CUSTOM_VLOG), ) +ifneq ($(CUSTOM_VLOG), ) OBJ_DIR ?= $(VLSI_OBJ_DIR)/custom-$(VLSI_TOP) else OBJ_DIR ?= $(VLSI_OBJ_DIR)/$(long_name)-$(VLSI_TOP) From f1346a2d91f2d2dc84f7aa7d36d3aa0f46510e08 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Fri, 22 Nov 2019 11:06:54 -0800 Subject: [PATCH 21/75] FireSim generator should also produce hwacha test suite makefrag rules --- generators/firechip/src/main/scala/Generator.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/generators/firechip/src/main/scala/Generator.scala b/generators/firechip/src/main/scala/Generator.scala index 0c5b4909..ceeb328c 100644 --- a/generators/firechip/src/main/scala/Generator.scala +++ b/generators/firechip/src/main/scala/Generator.scala @@ -18,6 +18,8 @@ import freechips.rocketchip.tile.XLen import firesim.util.{GeneratorArgs, HasTargetAgnosticUtilites, HasFireSimGeneratorUtilities} +import scala.util.Try + import utilities.TestSuiteHelper trait HasTestSuites { @@ -28,6 +30,14 @@ trait HasTestSuites { TestGeneration.addSuite(SlowBlockdevTests) if (!targetName.contains("NoNIC")) TestGeneration.addSuite(NICLoopbackTests) + + import hwacha.HwachaTestSuites._ + if (Try(params(hwacha.HwachaNLanes)).getOrElse(0) > 0) { + TestGeneration.addSuites(rv64uv.map(_("p"))) + TestGeneration.addSuites(rv64uv.map(_("vp"))) + TestGeneration.addSuite(rv64sv("p")) + TestGeneration.addSuite(hwachaBmarks) + } } } From 23d9c57c8273a6ef9403b1ad2fbcc3f3e99cbc22 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 22 Nov 2019 14:33:49 -0800 Subject: [PATCH 22/75] Bumped hammer --- vlsi/hammer | 2 +- vlsi/hammer-cadence-plugins | 2 +- vlsi/hammer-synopsys-plugins | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vlsi/hammer b/vlsi/hammer index 85c12e98..2f37cd31 160000 --- a/vlsi/hammer +++ b/vlsi/hammer @@ -1 +1 @@ -Subproject commit 85c12e98e63d599f5267c7711a24c174d74974c5 +Subproject commit 2f37cd3121d9a9e775efbe4554d9b74c30d01f61 diff --git a/vlsi/hammer-cadence-plugins b/vlsi/hammer-cadence-plugins index 5f5d9d9e..8f23bfa8 160000 --- a/vlsi/hammer-cadence-plugins +++ b/vlsi/hammer-cadence-plugins @@ -1 +1 @@ -Subproject commit 5f5d9d9e574d54acd3a84d1885c9f9b2897f373b +Subproject commit 8f23bfa8c971ceb39b10aa52d6c9f446c5303cd3 diff --git a/vlsi/hammer-synopsys-plugins b/vlsi/hammer-synopsys-plugins index e0ace734..f812f8ce 160000 --- a/vlsi/hammer-synopsys-plugins +++ b/vlsi/hammer-synopsys-plugins @@ -1 +1 @@ -Subproject commit e0ace7345e98e11b17ce550550c902782010e032 +Subproject commit f812f8ce85b5f77b563807bbb490b46ce82c1711 From a740f7b6f6c9ca2e2743fee3b6d59255a5a0d789 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Sat, 23 Nov 2019 13:11:09 -0800 Subject: [PATCH 23/75] bump spec --- software/spec2017 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/spec2017 b/software/spec2017 index f5cbc4aa..b8643136 160000 --- a/software/spec2017 +++ b/software/spec2017 @@ -1 +1 @@ -Subproject commit f5cbc4aaa536afac383d554df28291a7d27c57be +Subproject commit b86431364360a9e64487e5dec2962c48bafb67ff From 3bc0e7856fe56a9240beccf6f1ed735e898583da Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sat, 23 Nov 2019 17:50:22 -0800 Subject: [PATCH 24/75] [ci] Whitelist submodule dev branches to enable running submodule-commit checks on dev This works by checking the $CIRCLE_BRANCH env-var, which is set automatically by CircleCI. Annoyingly, this is set to the name of the source branch for a merge, rather than the target branch. The behavior of this check for each branch type is listed: if CIRCLE_BRANCH == "master": This CI run is the nightly CI run for the master branch. Make sure all submodules of the master branch point to master else if CIRCLE_BRANCH == "dev": This CI run is most likely somebody doing a dev->master merge. Make sure all submodules of the dev branch point to master else: This CI run is likely somebody merging a feature branch into dev. Allow submodule pointers of the dev branch to point to master OR dev --- .circleci/check-commit.sh | 78 +++++++++++++++++++++++++++++---------- .circleci/config.yml | 2 + 2 files changed, 61 insertions(+), 19 deletions(-) diff --git a/.circleci/check-commit.sh b/.circleci/check-commit.sh index ad7be185..dbf2a718 100755 --- a/.circleci/check-commit.sh +++ b/.circleci/check-commit.sh @@ -23,55 +23,94 @@ status=$(git submodule status) all_names=() + +search_submodule() { + echo "Running check on submodule $submodule in $dir" + hash=$(echo "$status" | grep "$dir.*$submodule " | awk '{print$1}' | grep -o "[[:alnum:]]*") + for branch in "${branches[@]}" + do + echo "Searching for $hash in origin/$branch of $submodule" + (git -C $dir/$submodule branch -r --contains "$hash" | grep "origin/$branch") && true # needs init'ed submodules + if [ $? -eq 0 ] + then + all_names+=("$dir/$submodule $hash 0") + return + fi + done + all_names+=("$dir/$submodule $hash 1") + return +} + search () { for submodule in "${submodules[@]}" do - echo "Running check on submodule $submodule in $dir" - hash=$(echo "$status" | grep "$dir.*$submodule " | awk '{print$1}' | grep -o "[[:alnum:]]*") - echo "Searching for $hash in origin/$branch of $submodule" - (git -C $dir/$submodule branch -r --contains "$hash" | grep "origin/$branch") && true # needs init'ed submodules - all_names+=("$dir/$submodule $hash $?") + search_submodule done } -submodules=("boom" "hwacha" "icenet" "rocket-chip" "sifive-blocks" "sifive-cache" "testchipip") +submodules=("boom" "hwacha" "icenet" "sha3" "rocket-chip" "sifive-blocks" "sifive-cache" "testchipip") dir="generators" -branch="master" - +if [ "$CIRCLE_BRANCH" == "master" ] || [ "$CIRCLE_BRANCH" == "dev" ] +then + branches=("master") +else + branches=("master" "dev") +fi search submodules=("riscv-gnu-toolchain" "riscv-isa-sim" "riscv-pk" "riscv-tests") dir="toolchains/esp-tools" -branch="master" - +branches=("master") search submodules=("riscv-gnu-toolchain" "riscv-isa-sim" "riscv-pk" "riscv-tests" "riscv-gnu-toolchain-prebuilt") dir="toolchains/riscv-tools" -branch="master" - +branches=("master") search # riscv-openocd doesn't use its master branch submodules=("riscv-openocd") dir="toolchains/riscv-tools" -branch="riscv" - +branches=("riscv") search -submodules=("barstools" "chisel3" "firrtl" "torture") -dir="tools" -branch="master" +submodules=("qemu") +dir="toolchains" +branches=("master") +search +submodules=("spec2017" "coremark") +dir="software" +branches=("master") +search + +submodules=("axe" "barstools" "chisel3" "firrtl" "torture" "dsptools" "chisel-testers" "treadle" "firrtl-interpreter") +dir="tools" +if [ "$CIRCLE_BRANCH" == "master" ] || [ "$CIRCLE_BRANCH" == "dev" ] +then + branches=("master") +else + branches=("master" "dev") +fi search submodules=("firesim") dir="sims" -branch="master" - +if [ "$CIRCLE_BRANCH" == "master" ] || [ "$CIRCLE_BRANCH" == "dev" ] +then + branches=("master") +else + branches=("master" "dev") +fi search +submodules=("hammer") +dir="vlsi" +branches=("master") +search + + # turn off verbose printing to make this easier to read set +x @@ -90,3 +129,4 @@ do done echo "Done checking all submodules" + diff --git a/.circleci/config.yml b/.circleci/config.yml index d6d8097b..95de63a4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -622,6 +622,8 @@ workflows: # Build verilator - install-verilator + - commit-on-master-check + # Build extra tests - build-extra-tests: requires: From 2468da282e3b29cf082dd51b151e33921f759476 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Sat, 23 Nov 2019 18:56:38 -0800 Subject: [PATCH 25/75] dont ctags within toolchains/sim | only ctags scala/C/C++/python files --- .ctagsignore | 2 ++ scripts/gen-tags.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.ctagsignore b/.ctagsignore index c910d58a..c1b3fb23 100644 --- a/.ctagsignore +++ b/.ctagsignore @@ -1 +1,3 @@ */target +sims +toolchains diff --git a/scripts/gen-tags.sh b/scripts/gen-tags.sh index afc7e228..80d0365f 100755 --- a/scripts/gen-tags.sh +++ b/scripts/gen-tags.sh @@ -14,4 +14,4 @@ # * tags file in the directory that this was called in # ctags wrapper -ctags -R --exclude=@.ctagsignore --links=no +ctags -R --exclude=@.ctagsignore --links=no --languages=scala,C,C++,python From 33a4a9726d4af4f900b90f3c49c2d413dff7c0de Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Wed, 4 Dec 2019 11:18:21 -0800 Subject: [PATCH 26/75] [boom] bump boom --- generators/boom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/boom b/generators/boom index 2a0ea2e7..397992d5 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit 2a0ea2e7acfd4605eed513e15062848e4e5be309 +Subproject commit 397992d535d14d38658e8503a5ededa3430bb352 From c0564d319b932e8f2a886ae199d6144547a7818c Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Mon, 9 Dec 2019 21:06:57 -0800 Subject: [PATCH 27/75] Control Core Example (#361) * [example] add control core config example * [example] move control core to last hartid * [example] expand MaxHartIdBits when adding a core --- .../example/src/main/scala/ConfigMixins.scala | 35 +++++++++++++++++-- .../src/main/scala/HeteroConfigs.scala | 11 ++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/generators/example/src/main/scala/ConfigMixins.scala b/generators/example/src/main/scala/ConfigMixins.scala index 7d7e74af..25104079 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -4,10 +4,11 @@ import chisel3._ import chisel3.util.{log2Up} import freechips.rocketchip.config.{Field, Parameters, Config} -import freechips.rocketchip.subsystem.{RocketTilesKey, WithRoccExample, WithNMemoryChannels, WithNBigCores, WithRV32} +import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, WithRoccExample, WithNMemoryChannels, WithNBigCores, WithRV32, CacheBlockBytes} import freechips.rocketchip.diplomacy.{LazyModule, ValName} import freechips.rocketchip.devices.tilelink.BootROMParams -import freechips.rocketchip.tile.{XLen, BuildRoCC, TileKey, LazyRoCC} +import freechips.rocketchip.tile.{RocketTileParams, MaxHartIdBits, XLen, BuildRoCC, TileKey, LazyRoCC} +import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams, ICacheParams} import boom.common.{BoomTilesKey} @@ -182,3 +183,33 @@ class WithInitZeroTop extends Config((site, here, up) => { Module(LazyModule(new TopWithInitZero()(p)).module) }) // DOC include end: WithInitZero + +/** + * Mixin to add a small Rocket core to the system as a "control" core. + * Used as an example of a PMU core. + */ +class WithControlCore extends Config((site, here, up) => { + case RocketTilesKey => up(RocketTilesKey, site) :+ + RocketTileParams( + core = RocketCoreParams( + useVM = false, + fpu = None, + mulDiv = Some(MulDivParams(mulUnroll = 8))), + btb = None, + dcache = Some(DCacheParams( + rowBits = site(SystemBusKey).beatBits, + nSets = 64, + nWays = 1, + nTLBEntries = 4, + nMSHRs = 0, + blockBytes = site(CacheBlockBytes))), + icache = Some(ICacheParams( + rowBits = site(SystemBusKey).beatBits, + nSets = 64, + nWays = 1, + nTLBEntries = 4, + blockBytes = site(CacheBlockBytes))), + hartId = up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + ) + case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) +}) diff --git a/generators/example/src/main/scala/HeteroConfigs.scala b/generators/example/src/main/scala/HeteroConfigs.scala index a9443c2e..84da15b3 100644 --- a/generators/example/src/main/scala/HeteroConfigs.scala +++ b/generators/example/src/main/scala/HeteroConfigs.scala @@ -98,3 +98,14 @@ class DualLargeBoomAndDualRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(2) ++ // 2 rocket cores new freechips.rocketchip.system.BaseConfig) // DOC include end: DualBoomAndRocket + +class MultiCoreWithControlCoreConfig extends Config( + new WithTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new WithControlCore ++ // add small control core (last hartid) + new boom.common.WithRenumberHarts ++ + new boom.common.WithLargeBooms ++ + new boom.common.WithNBoomCores(2) ++ // 2 normal boom cores + new freechips.rocketchip.subsystem.WithNBigCores(2) ++ // 2 normal rocket cores + new freechips.rocketchip.system.BaseConfig) From 86a473dbf6e596d092d57e9c199bca053020f326 Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Thu, 12 Dec 2019 13:39:09 -0800 Subject: [PATCH 28/75] Bump all submodules for chisel 3.2.0 and rocket-chip august-2019 (#358) * Bump all submodules for chisel 3.2.0 and rocket-chip august-2019 * Fix subprojects that aren't tested from normal sims * Fix firechip for chisel 3.2.0 and rc bump * Bump boom for bug fix rebase * [sbt] Don't rely on target-rtl symlink when FireSim is top [no ci] * Bump boom for rc bump fix to bug fix * Bump FireSim for CI check * Bump FireSim * Bump submodules after merge --- build.sbt | 15 +++++++++------ generators/boom | 2 +- generators/example/src/main/scala/Generator.scala | 2 +- .../example/src/main/scala/TestHarness.scala | 6 +++--- .../firechip/src/main/scala/BridgeBinders.scala | 4 ++-- .../firechip/src/main/scala/Generator.scala | 6 +++--- .../firechip/src/main/scala/TargetConfigs.scala | 4 ++-- generators/hwacha | 2 +- generators/icenet | 2 +- generators/rocket-chip | 2 +- generators/sha3 | 2 +- generators/sifive-blocks | 2 +- generators/sifive-cache | 2 +- generators/testchipip | 2 +- .../tracegen/src/main/scala/TestHarness.scala | 2 +- .../utilities/src/main/scala/Subsystem.scala | 2 +- sims/firesim | 2 +- tools/barstools | 2 +- tools/chisel-testers | 2 +- tools/chisel3 | 2 +- tools/firrtl | 2 +- variables.mk | 2 +- 22 files changed, 36 insertions(+), 33 deletions(-) diff --git a/build.sbt b/build.sbt index ae77dead..e252cfa9 100644 --- a/build.sbt +++ b/build.sbt @@ -7,14 +7,14 @@ lazy val chipyardRoot = RootProject(file(".")) lazy val commonSettings = Seq( organization := "edu.berkeley.cs", version := "1.0", - scalaVersion := "2.12.4", + scalaVersion := "2.12.10", traceLevel := 15, test in assembly := {}, assemblyMergeStrategy in assembly := { _ match { case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard case _ => MergeStrategy.first}}, scalacOptions ++= Seq("-deprecation","-unchecked","-Xsource:2.11"), - libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % "test", + libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % "test", libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.1", libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value, libraryDependencies += "com.github.scopt" %% "scopt" % "3.7.0", @@ -35,7 +35,7 @@ lazy val firesimAsLibrary = sys.env.get("FIRESIM_STANDALONE") == None lazy val firesimDir = if (firesimAsLibrary) { file("sims/firesim/sim/") } else { - file("../../") + file("../../sim") } // Checks for -DROCKET_USE_MAVEN. @@ -111,9 +111,12 @@ lazy val hardfloat = (project in rocketChipDir / "hardfloat") lazy val rocketMacros = (project in rocketChipDir / "macros") .settings(commonSettings) +lazy val rocketConfig = (project in rocketChipDir / "api-config-chipsalliance/build-rules/sbt") + .settings(commonSettings) + lazy val rocketchip = freshProject("rocketchip", rocketChipDir) .settings(commonSettings) - .dependsOn(chisel, hardfloat, rocketMacros) + .dependsOn(chisel, hardfloat, rocketMacros, rocketConfig) lazy val testchipip = (project in file("generators/testchipip")) .dependsOn(rocketchip) @@ -181,7 +184,7 @@ lazy val sifive_blocks = (project in file("generators/sifive-blocks")) lazy val sifive_cache = (project in file("generators/sifive-cache")).settings( commonSettings, - scalaSource in Compile := baseDirectory.value / "craft" + scalaSource in Compile := baseDirectory.value / "design/craft" ).dependsOn(rocketchip) // Library components of FireSim @@ -189,7 +192,7 @@ lazy val midas = ProjectRef(firesimDir, "midas") lazy val firesimLib = ProjectRef(firesimDir, "firesimLib") lazy val firechip = (project in file("generators/firechip")) - .dependsOn(example, icenet, testchipip, tracegen, midasTargetUtils, midas, firesimLib % "test->test;compile->compile") + .dependsOn(boom, hwacha, example, icenet, testchipip, sifive_blocks, sifive_cache, sha3, utilities, tracegen, midasTargetUtils, midas, firesimLib % "test->test;compile->compile") .settings( commonSettings, testGrouping in Test := isolateAllTests( (definedTests in Test).value ) diff --git a/generators/boom b/generators/boom index 397992d5..63b430bf 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit 397992d535d14d38658e8503a5ededa3430bb352 +Subproject commit 63b430bf350fd2c272ca6b42b0a797770205ad06 diff --git a/generators/example/src/main/scala/Generator.scala b/generators/example/src/main/scala/Generator.scala index 7c6b5168..9beb094c 100644 --- a/generators/example/src/main/scala/Generator.scala +++ b/generators/example/src/main/scala/Generator.scala @@ -31,7 +31,7 @@ object Generator extends GeneratorApp { } // specify the name that the generator outputs files as - val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs + override lazy val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs // generate files generateFirrtl diff --git a/generators/example/src/main/scala/TestHarness.scala b/generators/example/src/main/scala/TestHarness.scala index 61807f2e..292d1bd1 100644 --- a/generators/example/src/main/scala/TestHarness.scala +++ b/generators/example/src/main/scala/TestHarness.scala @@ -30,7 +30,7 @@ class TestHarness(implicit val p: Parameters) extends Module { val dut = p(BuildTop)(clock, reset.toBool, p) - dut.debug := DontCare + dut.debug.foreach(_ := DontCare) dut.connectSimAXIMem() dut.connectSimAXIMMIO() dut.dontTouchPorts() @@ -65,7 +65,7 @@ class TestHarnessWithDTM(implicit p: Parameters) extends Module val dut = p(BuildTopWithDTM)(clock, reset.toBool, p) - dut.reset := reset.asBool | dut.debug.ndreset + dut.reset := reset.asBool | dut.debug.get.ndreset dut.connectSimAXIMem() dut.connectSimAXIMMIO() dut.dontTouchPorts() @@ -83,5 +83,5 @@ class TestHarnessWithDTM(implicit p: Parameters) extends Module } }) - Debug.connectDebug(dut.debug, clock, reset.asBool, io.success) + Debug.connectDebug(dut.debug, dut.psd, clock, reset.asBool, io.success) } diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index 95133561..c3a6ca80 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -21,13 +21,13 @@ import firesim.util.RegisterBridgeBinder import tracegen.HasTraceGenTilesModuleImp class WithTiedOffDebug extends RegisterBridgeBinder({ case target: HasPeripheryDebugModuleImp => - target.debug.clockeddmi.foreach({ cdmi => + target.debug.foreach(_.clockeddmi.foreach({ cdmi => cdmi.dmi.req.valid := false.B cdmi.dmi.req.bits := DontCare cdmi.dmi.resp.ready := false.B cdmi.dmiClock := false.B.asClock cdmi.dmiReset := false.B - }) + })) Seq() }) diff --git a/generators/firechip/src/main/scala/Generator.scala b/generators/firechip/src/main/scala/Generator.scala index ceeb328c..dd5b432d 100644 --- a/generators/firechip/src/main/scala/Generator.scala +++ b/generators/firechip/src/main/scala/Generator.scala @@ -4,7 +4,7 @@ package firesim.firesim import java.io.{File, FileWriter} -import chisel3.experimental.RawModule +import chisel3.RawModule import chisel3.internal.firrtl.{Circuit, Port} import freechips.rocketchip.diplomacy.{ValName, AutoBundle} @@ -58,7 +58,7 @@ trait IsFireSimGeneratorLike extends HasFireSimGeneratorUtilities with HasTestSu } object FireSimGenerator extends App with IsFireSimGeneratorLike { - val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs + override lazy val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs lazy val generatorArgs = GeneratorArgs(args) lazy val genDir = new File(names.targetDir) // The only reason this is not generateFirrtl; generateAnno is that we need to use a different @@ -70,7 +70,7 @@ object FireSimGenerator extends App with IsFireSimGeneratorLike { // For now, provide a separate generator app when not specifically building for FireSim object Generator extends freechips.rocketchip.util.GeneratorApp with HasTestSuites { - val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs + override lazy val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs generateFirrtl generateAnno generateTestSuiteMakefrags diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 37df3799..4541578d 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -10,7 +10,7 @@ import freechips.rocketchip.tilelink._ import freechips.rocketchip.rocket.DCacheParams import freechips.rocketchip.subsystem._ import freechips.rocketchip.devices.tilelink.BootROMParams -import freechips.rocketchip.devices.debug.DebugModuleParams +import freechips.rocketchip.devices.debug.{DebugModuleParams, DebugModuleKey} import boom.common.BoomTilesKey import testchipip.{BlockDeviceKey, BlockDeviceConfig} import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} @@ -77,7 +77,7 @@ class WithBoomL2TLBs(entries: Int) extends Config((site, here, up) => { // Disables clock-gating; doesn't play nice with our FAME-1 pass class WithoutClockGating extends Config((site, here, up) => { - case DebugModuleParams => up(DebugModuleParams, site).copy(clockGate = false) + case DebugModuleKey => up(DebugModuleKey, site).map(_.copy(clockGate = false)) }) // Testing configurations diff --git a/generators/hwacha b/generators/hwacha index ff4605f5..ef5e5196 160000 --- a/generators/hwacha +++ b/generators/hwacha @@ -1 +1 @@ -Subproject commit ff4605f5d10d91b7ae8c4a006b965d4706009a06 +Subproject commit ef5e5196b685536890396a08a9f5024eb8b7928e diff --git a/generators/icenet b/generators/icenet index baa40ed8..77eb7eff 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit baa40ed85d7425ef5ce206d52fb8b2759c6f6827 +Subproject commit 77eb7eff2e6f39aa971f53f3c3ffbb27cc9bab2d diff --git a/generators/rocket-chip b/generators/rocket-chip index 50de8a34..4f0cdea8 160000 --- a/generators/rocket-chip +++ b/generators/rocket-chip @@ -1 +1 @@ -Subproject commit 50de8a34c19c12de5066cd7ada50ebb5f5b2ea26 +Subproject commit 4f0cdea85c8a2b849fd582ccc8497892001d06b0 diff --git a/generators/sha3 b/generators/sha3 index e27d808c..def77259 160000 --- a/generators/sha3 +++ b/generators/sha3 @@ -1 +1 @@ -Subproject commit e27d808cf1a637a8f2a80fc5dcde44c3d0a41c5c +Subproject commit def77259c0c78c05cd3d6104943f3e6d98da5bd2 diff --git a/generators/sifive-blocks b/generators/sifive-blocks index 24dd5378..1bc0ef18 160000 --- a/generators/sifive-blocks +++ b/generators/sifive-blocks @@ -1 +1 @@ -Subproject commit 24dd537894379dc160ed9e15d33444439822ab5b +Subproject commit 1bc0ef18d6653f1133cb9293e8ee8620f9417c78 diff --git a/generators/sifive-cache b/generators/sifive-cache index 13d0c2f1..f5a09e28 160000 --- a/generators/sifive-cache +++ b/generators/sifive-cache @@ -1 +1 @@ -Subproject commit 13d0c2f17853a658ae86eae793718c71ac82dddf +Subproject commit f5a09e289b92e53039d74114140d0380032ad8b4 diff --git a/generators/testchipip b/generators/testchipip index aa13f6cc..64408599 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit aa13f6ccc1a05a20e52a1600b6c8c796d306f1cd +Subproject commit 64408599a055f3f7cc6b2a90ae617e67b179b332 diff --git a/generators/tracegen/src/main/scala/TestHarness.scala b/generators/tracegen/src/main/scala/TestHarness.scala index 93da430b..5e07909f 100644 --- a/generators/tracegen/src/main/scala/TestHarness.scala +++ b/generators/tracegen/src/main/scala/TestHarness.scala @@ -17,7 +17,7 @@ class TestHarness(implicit p: Parameters) extends Module { object Generator extends GeneratorApp { // specify the name that the generator outputs files as - val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs + override lazy val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs // generate files generateFirrtl diff --git a/generators/utilities/src/main/scala/Subsystem.scala b/generators/utilities/src/main/scala/Subsystem.scala index 560caa4c..d5354946 100644 --- a/generators/utilities/src/main/scala/Subsystem.scala +++ b/generators/utilities/src/main/scala/Subsystem.scala @@ -66,7 +66,7 @@ trait HasBoomAndRocketTiles extends HasTiles def treeNode: RocketTileLogicalTreeNode = new RocketTileLogicalTreeNode(rocketLogicalTree.getOMInterruptTargets) LogicalModuleTree.add(logicalTreeNode, rocketLogicalTree) - connectInterrupts(tile, Some(debug), clintOpt, plicOpt) + connectInterrupts(tile, debugOpt, clintOpt, plicOpt) tile } diff --git a/sims/firesim b/sims/firesim index cfeb0e67..d799550b 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit cfeb0e67fe58f896b95459e110802903fed5145a +Subproject commit d799550b42c4bf0a1030cf93dde3a27263bfcc95 diff --git a/tools/barstools b/tools/barstools index 3bba55cc..5198b388 160000 --- a/tools/barstools +++ b/tools/barstools @@ -1 +1 @@ -Subproject commit 3bba55ccc89518ddeb3ed78774dd6e68d938c07a +Subproject commit 5198b3883c8dfb744c24e7586eec5c9e80a8dd68 diff --git a/tools/chisel-testers b/tools/chisel-testers index 41f4eef0..f410c593 160000 --- a/tools/chisel-testers +++ b/tools/chisel-testers @@ -1 +1 @@ -Subproject commit 41f4eef0d85b65fabd0d786efa8baa099513dcf0 +Subproject commit f410c59316e5c43bac96411889aba8c5ab9a8fc0 diff --git a/tools/chisel3 b/tools/chisel3 index e1aa5f3f..d1a61262 160000 --- a/tools/chisel3 +++ b/tools/chisel3 @@ -1 +1 @@ -Subproject commit e1aa5f3f5c0cdeb204047c3ca50801d9f7ea25f1 +Subproject commit d1a61262630b5ea77ebe21a453df9645cb7e4185 diff --git a/tools/firrtl b/tools/firrtl index 84a1c7b1..f738fbe8 160000 --- a/tools/firrtl +++ b/tools/firrtl @@ -1 +1 @@ -Subproject commit 84a1c7b1f7311ce036cb7d3d5eb652466b87dce4 +Subproject commit f738fbe8667ed6b76ec00a15960b9c3a42b8654a diff --git a/variables.mk b/variables.mk index fca782fa..a303eafe 100644 --- a/variables.mk +++ b/variables.mk @@ -140,7 +140,7 @@ JAVA_ARGS ?= -Xmx$(JAVA_HEAP_SIZE) -Xss8M -XX:MaxPermSize=256M ######################################################################################### # default sbt launch command ######################################################################################### -SCALA_VERSION=2.12.4 +SCALA_VERSION=2.12.10 SCALA_VERSION_MAJOR=$(basename $(SCALA_VERSION)) SBT ?= java $(JAVA_ARGS) -jar $(ROCKETCHIP_DIR)/sbt-launch.jar ++$(SCALA_VERSION) From 4d58321f1c374f4fd6b70233b090ff8c1d00dcc3 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Fri, 13 Dec 2019 11:38:49 -0800 Subject: [PATCH 29/75] Do not check that chisel3 and firrtl submodule branches are whitelisted (#366) Chisel3 and FIRRTL use release branches, which we track instead. --- .circleci/check-commit.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/check-commit.sh b/.circleci/check-commit.sh index dbf2a718..9f8c701b 100755 --- a/.circleci/check-commit.sh +++ b/.circleci/check-commit.sh @@ -85,7 +85,7 @@ dir="software" branches=("master") search -submodules=("axe" "barstools" "chisel3" "firrtl" "torture" "dsptools" "chisel-testers" "treadle" "firrtl-interpreter") +submodules=("axe" "barstools" "torture" "dsptools" "chisel-testers" "treadle" "firrtl-interpreter") dir="tools" if [ "$CIRCLE_BRANCH" == "master" ] || [ "$CIRCLE_BRANCH" == "dev" ] then From 72f9730cbd99f34cec6aae0df1c968c34b208f26 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Fri, 13 Dec 2019 11:40:47 -0800 Subject: [PATCH 30/75] Allow user to specify toolchain install prefix (#334) --- .circleci/config.yml | 46 ++++++++++++++++---------------- scripts/build-toolchains.sh | 53 ++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 48 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 95de63a4..bb5b3a50 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,14 +31,14 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - run: name: Building riscv-tools toolchain command: | .circleci/build-toolchains.sh riscv-tools no_output_timeout: 120m - save_cache: - key: riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + key: riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} paths: - "/home/riscvuser/riscv-tools-install" install-esp-toolchain: @@ -55,14 +55,14 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - esp-tools-installed-v2-{{ checksum "../esp-tools.hash" }} + - esp-tools-installed-v3-{{ checksum "../esp-tools.hash" }} - run: name: Building esp-tools toolchain command: | .circleci/build-toolchains.sh esp-tools no_output_timeout: 120m - save_cache: - key: esp-tools-installed-v2-{{ checksum "../esp-tools.hash" }} + key: esp-tools-installed-v3-{{ checksum "../esp-tools.hash" }} paths: - "/home/riscvuser/esp-tools-install" install-verilator: @@ -105,7 +105,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - run: name: Build extra tests command: .circleci/build-extra-tests.sh @@ -131,7 +131,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -160,7 +160,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -189,7 +189,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -218,7 +218,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -247,7 +247,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -276,7 +276,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - esp-tools-installed-v2-{{ checksum "../esp-tools.hash" }} + - esp-tools-installed-v3-{{ checksum "../esp-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -305,7 +305,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -334,7 +334,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -363,7 +363,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -389,7 +389,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -410,7 +410,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - example-{{ .Branch }}-{{ .Revision }} @@ -434,7 +434,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - boomrocketexample-{{ .Branch }}-{{ .Revision }} @@ -458,7 +458,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - boom-{{ .Branch }}-{{ .Revision }} @@ -482,7 +482,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - rocketchip-{{ .Branch }}-{{ .Revision }} @@ -506,7 +506,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - esp-tools-installed-v2-{{ checksum "../esp-tools.hash" }} + - esp-tools-installed-v3-{{ checksum "../esp-tools.hash" }} - restore_cache: keys: - hwacha-{{ .Branch }}-{{ .Revision }} @@ -530,7 +530,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - tracegen-{{ .Branch }}-{{ .Revision }} @@ -554,7 +554,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - firesim-{{ .Branch }}-{{ .Revision }} @@ -581,7 +581,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - fireboom-{{ .Branch }}-{{ .Revision }} diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index 9d7b3deb..e858e452 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -10,10 +10,17 @@ RDIR=$(pwd) CHIPYARD_DIR="${CHIPYARD_DIR:-$(git rev-parse --show-toplevel)}" usage() { - echo "usage: ${0} [riscv-tools | esp-tools | ec2fast]" + echo "usage: ${0} [OPTIONS] [riscv-tools | esp-tools | ec2fast]" + echo "" + echo "Installation Types" echo " riscv-tools: if set, builds the riscv toolchain (this is also the default)" echo " esp-tools: if set, builds esp-tools toolchain used for the hwacha vector accelerator" echo " ec2fast: if set, pulls in a pre-compiled RISC-V toolchain for an EC2 manager instance" + echo "" + echo "Options" + echo " --prefix PREFIX : Install destination. If unset, defaults to $(pwd)/riscv-tools-install" + echo " or $(pwd)/esp-tools-install" + echo " --help -h : Display this message" exit "$1" } @@ -27,38 +34,34 @@ die() { TOOLCHAIN="riscv-tools" EC2FASTINSTALL="false" +RISCV="" -while getopts 'hH-:' opt ; do - case $opt in - h|H) - usage 3 ;; - -) - case $OPTARG in - help) +# getopts does not support long options, and is inflexible +while [ "$1" != "" ]; +do + case $1 in + -h | --help | help ) usage 3 ;; - ec2fast) # Preserve compatibility - EC2FASTINSTALL=true ;; - *) - error "invalid option: --${OPTARG}" + -p | --prefix ) + shift + RISCV=$(realpath $1) ;; + riscv-tools | esp-tools) + TOOLCHAIN=$1 ;; + ec2fast ) + EC2FASTINSTALL="true" ;; + * ) + error "invalid option $1" usage 1 ;; - esac ;; - *) - error "invalid option: -${opt}" - usage 1 ;; esac + shift done -shift $((OPTIND - 1)) - -if [ "$1" = ec2fast ] ; then - EC2FASTINSTALL=true -elif [ -n "$1" ] ; then - TOOLCHAIN="$1" +if [ -z "$RISCV" ] ; then + INSTALL_DIR="$TOOLCHAIN-install" + RISCV="$(pwd)/$INSTALL_DIR" fi -INSTALL_DIR="$TOOLCHAIN-install" - -RISCV="$(pwd)/$INSTALL_DIR" +echo "Installing toolchain to $RISCV" # install risc-v tools export RISCV="$RISCV" From 56770a1a4c21ff950a232065a44139afa1565d48 Mon Sep 17 00:00:00 2001 From: alonamid Date: Sat, 14 Dec 2019 01:36:42 -0800 Subject: [PATCH 31/75] Gemmini Integration (#356) * gemmini submodule * fix build.sbt * firechip gemmini config * bump gemmini * bump gemmini * bump gemmini * fix hwacha typo * start gemmini docs * bump gemmini * gemmini docs * Update Gemmini RST. Add quick-build instructions to Gemmini RST * start gemmini CI * bump gemmini * gemmini CI fixes * bump gemmini * fix simulator name in gemmini CI * cleanup gemmini CI * bump esp-isa-sim to include gemmini * update gemmini docs * [ci skip] fix gemmini docs typos * Update Gemmini.rst Add instructions on building Gemmini programs, or writing your own programs. * Changed order of VCS and Verilator in Gemmini docs * Remove "make your own tests" from Gemmini README * bump gemmini * try to fix midasexamples CI --- .circleci/check-commit.sh | 2 +- .circleci/config.yml | 62 ++++++++++++ .circleci/defaults.sh | 1 + .circleci/do-firesim-build.sh | 2 +- .circleci/do-rtl-build.sh | 2 +- .circleci/run-midasexamples-tests.sh | 2 +- .circleci/run-tests.sh | 12 +++ .gitmodules | 3 + build.sbt | 6 +- docs/Chipyard-Basics/Initial-Repo-Setup.rst | 2 + docs/Generators/Gemmini.rst | 90 ++++++++++++++++++ docs/Generators/Hwacha.rst | 2 +- docs/Generators/index.rst | 1 + docs/_static/images/gemmini-system.png | Bin 0 -> 115294 bytes .../_static/images/gemmini-systolic-array.png | Bin 0 -> 113148 bytes .../src/main/scala/RocketConfigs.scala | 10 ++ .../src/main/scala/TargetConfigs.scala | 12 +++ generators/gemmini | 1 + toolchains/esp-tools/riscv-isa-sim | 2 +- 19 files changed, 205 insertions(+), 7 deletions(-) create mode 100644 docs/Generators/Gemmini.rst create mode 100644 docs/_static/images/gemmini-system.png create mode 100644 docs/_static/images/gemmini-systolic-array.png create mode 160000 generators/gemmini diff --git a/.circleci/check-commit.sh b/.circleci/check-commit.sh index 9f8c701b..ed3093fd 100755 --- a/.circleci/check-commit.sh +++ b/.circleci/check-commit.sh @@ -48,7 +48,7 @@ search () { done } -submodules=("boom" "hwacha" "icenet" "sha3" "rocket-chip" "sifive-blocks" "sifive-cache" "testchipip") +submodules=("boom" "hwacha" "icenet" "sha3" "rocket-chip" "sifive-blocks" "sifive-cache" "testchipip" "gemmini") dir="generators" if [ "$CIRCLE_BRANCH" == "master" ] || [ "$CIRCLE_BRANCH" == "dev" ] then diff --git a/.circleci/config.yml b/.circleci/config.yml index bb5b3a50..75f13068 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -288,6 +288,35 @@ jobs: key: hwacha-{{ .Branch }}-{{ .Revision }} paths: - "/home/riscvuser/project" + prepare-gemmini: + docker: + - image: riscvboom/riscvboom-images:0.0.12 + environment: + JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit + TERM: dumb + steps: + - add_ssh_keys: + fingerprints: + - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" + - checkout + - run: + name: Create hash of toolchains + command: | + .circleci/create-hash.sh + - restore_cache: + keys: + - esp-tools-installed-v2-{{ checksum "../esp-tools.hash" }} + - restore_cache: + keys: + - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + - run: + name: Building the gemmini subproject using Verilator + command: .circleci/do-rtl-build.sh gemmini + no_output_timeout: 120m + - save_cache: + key: gemmini-{{ .Branch }}-{{ .Revision }} + paths: + - "/home/riscvuser/project" prepare-tracegen: docker: - image: riscvboom/riscvboom-images:0.0.12 @@ -516,6 +545,30 @@ jobs: - run: name: Run hwacha tests command: .circleci/run-tests.sh hwacha + gemmini-run-tests: + docker: + - image: riscvboom/riscvboom-images:0.0.12 + environment: + JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit + TERM: dumb + steps: + - checkout + - run: + name: Create hash of toolchains + command: | + .circleci/create-hash.sh + - restore_cache: + keys: + - esp-tools-installed-v2-{{ checksum "../esp-tools.hash" }} + - restore_cache: + keys: + - gemmini-{{ .Branch }}-{{ .Revision }} + - restore_cache: + keys: + - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + - run: + name: Run gemmini tests + command: .circleci/run-tests.sh gemmini tracegen-run-tests: docker: - image: riscvboom/riscvboom-images:0.0.12 @@ -660,6 +713,11 @@ workflows: - install-esp-toolchain - install-verilator + - prepare-gemmini: + requires: + - install-esp-toolchain + - install-verilator + - prepare-tracegen: requires: - install-riscv-toolchain @@ -704,6 +762,10 @@ workflows: requires: - prepare-hwacha + - gemmini-run-tests: + requires: + - prepare-gemmini + - tracegen-run-tests: requires: - prepare-tracegen diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index ffd45ffb..87a761d9 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -47,6 +47,7 @@ mapping["boom"]="SUB_PROJECT=example CONFIG=SmallBoomConfig" mapping["rocketchip"]="SUB_PROJECT=rocketchip" mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=SimBlockDeviceRocketConfig TOP=TopWithBlockDevice" mapping["hwacha"]="SUB_PROJECT=example CONFIG=HwachaRocketConfig" +mapping["gemmini"]="SUB_PROJECT=example CONFIG=GemminiRocketConfig" mapping["tracegen"]="SUB_PROJECT=tracegen CONFIG=NonBlockingTraceGenL2Config" mapping["firesim"]="DESIGN=FireSim TARGET_CONFIG=DDR3FRFCFSLLC4MB_FireSimRocketChipConfig PLATFORM_CONFIG=BaseF1Config" mapping["fireboom"]="DESIGN=FireSim TARGET_CONFIG=DDR3FRFCFSLLC4MB_FireSimBoomConfig PLATFORM_CONFIG=BaseF1Config" diff --git a/.circleci/do-firesim-build.sh b/.circleci/do-firesim-build.sh index 5eb42e56..8114355f 100755 --- a/.circleci/do-firesim-build.sh +++ b/.circleci/do-firesim-build.sh @@ -34,7 +34,7 @@ TOOLS_DIR=$REMOTE_RISCV_DIR LD_LIB_DIR=$REMOTE_RISCV_DIR/lib VERILATOR_BIN_DIR=$REMOTE_VERILATOR_DIR/install/bin -if [ $1 = "hwacha" ]; then +if [ $1 = "hwacha" ] || [ $1 = "gemmini" ]; then TOOLS_DIR=$REMOTE_ESP_DIR LD_LIB_DIR=$REMOTE_ESP_DIR/lib run "mkdir -p $REMOTE_ESP_DIR" diff --git a/.circleci/do-rtl-build.sh b/.circleci/do-rtl-build.sh index 50f9ce94..dd667dfb 100755 --- a/.circleci/do-rtl-build.sh +++ b/.circleci/do-rtl-build.sh @@ -32,7 +32,7 @@ run "cp -r ~/.sbt $REMOTE_WORK_DIR" TOOLS_DIR=$REMOTE_RISCV_DIR LD_LIB_DIR=$REMOTE_RISCV_DIR/lib -if [ $1 = "hwacha" ]; then +if [ $1 = "hwacha" ] || [ $1 = "gemmini" ]; then TOOLS_DIR=$REMOTE_ESP_DIR LD_LIB_DIR=$REMOTE_ESP_DIR/lib run "mkdir -p $REMOTE_ESP_DIR" diff --git a/.circleci/run-midasexamples-tests.sh b/.circleci/run-midasexamples-tests.sh index 383a75ff..7d31ac11 100755 --- a/.circleci/run-midasexamples-tests.sh +++ b/.circleci/run-midasexamples-tests.sh @@ -12,7 +12,7 @@ trap clean EXIT cd $LOCAL_CHIPYARD_DIR ./scripts/init-submodules-no-riscv-tools.sh -cd sims/firesim/sim/midas && git submodule update --init +cd sims/firesim/sim/midas # set stricthostkeychecking to no (must happen before rsync) run "echo \"Ping $SERVER\"" diff --git a/.circleci/run-tests.sh b/.circleci/run-tests.sh index 138e2785..97789b4c 100755 --- a/.circleci/run-tests.sh +++ b/.circleci/run-tests.sh @@ -50,6 +50,18 @@ case $1 in export PATH=$RISCV/bin:$PATH make run-rv64uv-p-asm-tests -j$NPROC -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR ${mapping[$1]} ;; + gemmini) + export RISCV=$LOCAL_ESP_DIR + export LD_LIBRARY_PATH=$LOCAL_ESP_DIR/lib + export PATH=$RISCV/bin:$PATH + GEMMINI_SOFTWARE_DIR=$LOCAL_SIM_DIR/../../generators/gemmini/software/gemmini-rocc-tests + cd $GEMMINI_SOFTWARE_DIR + ./build.sh + cd $LOCAL_SIM_DIR + $LOCAL_SIM_DIR/simulator-example-GemminiRocketConfig $GEMMINI_SOFTWARE_DIR/build/bareMetalC/aligned-baremetal + $LOCAL_SIM_DIR/simulator-example-GemminiRocketConfig $GEMMINI_SOFTWARE_DIR/build/bareMetalC/raw_hazard-baremetal + $LOCAL_SIM_DIR/simulator-example-GemminiRocketConfig $GEMMINI_SOFTWARE_DIR/build/bareMetalC/mvin_mvout-baremetal + ;; tracegen) run_tracegen ${mapping[$1]} ;; diff --git a/.gitmodules b/.gitmodules index 14c593bb..7e6fca6f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -104,3 +104,6 @@ [submodule "software/coremark"] path = software/coremark url = https://github.com/ucb-bar/coremark-workload.git +[submodule "generators/gemmini"] + path = generators/gemmini + url = https://github.com/ucb-bar/gemmini diff --git a/build.sbt b/build.sbt index e252cfa9..2f27fdc1 100644 --- a/build.sbt +++ b/build.sbt @@ -123,7 +123,7 @@ lazy val testchipip = (project in file("generators/testchipip")) .settings(commonSettings) lazy val example = conditionalDependsOn(project in file("generators/example")) - .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities, sha3) + .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities, sha3, gemmini) .settings(commonSettings) lazy val tracegen = conditionalDependsOn(project in file("generators/tracegen")) @@ -150,6 +150,10 @@ lazy val sha3 = (project in file("generators/sha3")) .dependsOn(rocketchip, chisel_testers, midasTargetUtils) .settings(commonSettings) +lazy val gemmini = (project in file("generators/gemmini")) + .dependsOn(rocketchip, chisel_testers, testchipip) + .settings(commonSettings) + lazy val tapeout = conditionalDependsOn(project in file("./tools/barstools/tapeout/")) .dependsOn(chisel_testers, example) .settings(commonSettings) diff --git a/docs/Chipyard-Basics/Initial-Repo-Setup.rst b/docs/Chipyard-Basics/Initial-Repo-Setup.rst index ad5f1abd..1ab06c7a 100644 --- a/docs/Chipyard-Basics/Initial-Repo-Setup.rst +++ b/docs/Chipyard-Basics/Initial-Repo-Setup.rst @@ -21,6 +21,8 @@ After cloning this repo, you will need to initialize all of the submodules. cd chipyard ./scripts/init-submodules-no-riscv-tools.sh +.. _build-toolchains: + Building a Toolchain ------------------------ diff --git a/docs/Generators/Gemmini.rst b/docs/Generators/Gemmini.rst new file mode 100644 index 00000000..d90e6224 --- /dev/null +++ b/docs/Generators/Gemmini.rst @@ -0,0 +1,90 @@ +Gemmini +==================================== + +The Gemmini project is developing a systolic-array based matrix multiplication unit generator for the investigation of software/hardware implications of such integrated SoC accelerators. It is inspired by recent trends in machine learning accelerators for edge and mobile SoCs. + +Gemmini is implemented as a RoCC accelerator with non-standard RISC-V custom instructions. The Gemmini unit uses the RoCC port of a Rocket or BOOM `tile`, and by default connects to the memory system through the System Bus (i.e., directly to the L2 cache). + +To add a Gemmini unit to an SoC, you should add the ``gemmini.DefaultGemminiConfig`` config mixin to the SoC configurations. To change the configuration of the Gemmini accelerator unit, you can write a custom configuration to replace the ``DefaultGemminiConfig``, which you can view under `generators/gemmini/src/main/scala/configs.scala `__ to see the possible configuration parameters. + +The example Chipyard config includes the following example SoC configuration which includes Gemmini: + +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala + :language: scala + :start-after: DOC include start: GemminiRocketConfig + :end-before: DOC include end: GemminiRocketConfig + +To build a simulation of this example Chipyard config, run the following commands: + +.. code-block:: shell + + cd sims/verilator # or "cd sims/vcs" + make CONFIG=GemminiRocketConfig + +.. image:: ../_static/images/gemmini-system.png + +Generator Parameters +-------------------------- + +Major parameters of interest include: + +* Systolic array dimensions (``tileRows``, ``tileColumns``, ``meshRows``, ``meshColumns``): The systolic array is composed of a 2-level hierarchy, in which each tile is fully combinational, while a mesh of tiles has pipeline registers between each tile. + +.. image:: ../_static/images/gemmini-systolic-array.png + +* Dataflow parameters (``dataflow``): Determine whether the systolic array in Gemmini is output-stationary or weight-stationary, or whether it supports both dataflows so that programmers may choose between them at runtime. + +* Scratchpad and accumulator memory parameters (``sp_banks``, ``sp_capacity``, ``acc_capacity``): Determine the properties of the Gemmini scratchpad memory: overall capacity of the scratchpad or accumulators (in KiB), and the number of banks the scratchpad is divided into. + +* Type parameters (``inputType``, ``outputType``, ``accType``): Determine the data-types flowing through different parts of a Gemmini accelerator. For example, ``inputType`` may be an 8-bit fixed-point number, while ``accType``, which determines the type of partial accumulations in a matrix multiplication, may be a 32-bit integer. ``outputType`` only determines the type of the data passed between two processing elements (PEs); for example, an 8-bit multiplication may produce a 16-bit result which must be shared between PEs in a systolic array. + +* Access-execute queue parameters (``ld_queue_length``, ``st_queue_length``, ``ex_queue_length``, ``rob_entries``): To implement access-execute decoupling, a Gemmini accelerator has a load instruction queue, a store instruction queue, and an execute instruction queue. The relative sizes of these queue determine the level of access-execute decoupling. Gemmini also implements a reorder buffer (ROB) - the number of entries in the ROB determines possible dependency management limitations. + +* DMA parameters (``dma_maxbytes``, ``dma_buswidth``, ``mem_pipeline``): Gemmini implements a DMA to move data from main memory to the Gemmini scratchpad, and from the Gemmini accumulators to main memory. The size of these DMA transactions is determined by the DMA parameters. These DMA parameters are tightly coupled with Rocket Chip SoC system parameters: in particular ``dma_buswidth`` is associated with the ``SystemBusKey`` ``beatBytes`` parameter, and ``dma_maxbytes`` is associated with ``cacheblockbytes`` Rocket Chip parameters. + +Software +------------------ + +The Gemmini non-standard ISA extension is specified in the `Gemmini repository `__. +The ISA includes configuration instructions, data movement instructions (from main memory to the Gemmini scratchpad, and from the Gemmini accumulators to main memory), and matrix multiplication execution instructions. + +Since Gemmini instructions are not exposed through the GNU binutils assembler, several C macros are provided in order to construct the instruction encodings to call these instructions. + +The Gemmini generator includes a C matrix multiplication library which wraps the calls to the custom Gemmini instructions. +The ``software`` directory of the generator includes the aforementioned library and macros, as well as bare-metal tests, and some FireMarshal workloads to run the tests in a Linux environment. In particular, the matrix multiplication C library can be found in the ``software/gemmini-rocc-tests/include/gemmini.h`` file. + +The Gemmini generator generates a C header file based on the generator parameters. This header files gets compiled together with the matrix multiplication library to tune library performance. The generated header file can be found under ``software/gemmini-rocc-tests/include/gemmini_params.h`` + +Build and Run Gemmini Tests +^^^^^^^^^^^^^^^^^^^^^^^^^ + +To build Gemmini tests: + +.. code-block:: shell + + cd generators/gemmini/software/gemmini-rocc-tests/ + ./build.sh + +Afterwards, the test binaries will be found in ``generators/gemmini/software/gemmini-rocc-tests/build``. Binaries whose names end in ``-baremetal`` are meant to be run in a bare-metal environment, while binaries whose names end in ``-linux`` are meant to run in a Linux environment. You can run the tests either on a cycle-accurate RTL simulator, or on a (much faster) functional ISA simulator called Spike. + +The Gemmini generator implements a custom non-standard version of Spike. This implementation is found within the ``esp-tools`` Spike implementation, together with the Hwacha vector accelerator non-standard ISA-extension. In order to use this version of Spike, please make sure to build the ``esp-tools`` software toolchain, as described in :ref:`build-toolchains`. + +In order to run Spike with the gemmini functional model, you will need to use the ``--extension=gemmini`` flag. For example: + +.. code-block:: shell + + spike --extension=gemmini + +Spike is built by default without a commit log. However, if you would like to add detailed functional log of gemmini operation to the spike model, you can rebuild spike manually (based on the instructions in the ``esp-tools/riscv-isa-sim/README`` file), with the ``--enable-gemminicommitlog`` option added to the ``configure`` step. + +Alternative SoC Configs +-------------------------- + +The Gemmini generator includes additional alternative SoC configs (configs that are not in the Chipyard example project). +If you would like to build one of these alternative SoC configurations which are defined in within the Gemmini project repository, you can run the following commands. These commands are similar to the one required when building a simulation from the example project, but they specify that the location of the configs are in the Gemmini subproject, as opposed to the Chipyard example project: + +.. code-block:: shell + + cd sims/verilator # or "cd sims/vcs" + make CONFIG=GemminiAcceleratorConfig CONFIG_PACKAGE=gemmini MODEL_PACKAGE=freechips.rocketchip.system GENERATOR_PACKAGE=freechips.rocketchip.system TOP=ExampleRocketSystem + diff --git a/docs/Generators/Hwacha.rst b/docs/Generators/Hwacha.rst index 240d6fc9..ac4f4fdf 100644 --- a/docs/Generators/Hwacha.rst +++ b/docs/Generators/Hwacha.rst @@ -11,5 +11,5 @@ To add the Hwacha vector unit to an SoC, you should add the ``hwacha.DefaultHwac To change the configuration of the Hwacha vector unit, you can write a custom configuration to replace the ``DefaultHwachaConfig``. You can view the ``DefaultHwachaConfig`` under `generators/hwacha/src/main/scala/configs.scala `__ to see the possible configuration parameters. -Since Hwacha implements a non-standard RISC-V extension, it requires a unique software toolchain to be able to compile and asseble its vector instructions. +Since Hwacha implements a non-standard RISC-V extension, it requires a unique software toolchain to be able to compile and assemble its vector instructions. To install the Hwacha toolchain, run the ``./scripts/build-toolchains.sh esp-tools`` command within the root Chipyard directory. This may take a while, and it will install the ``esp-tools-install`` directory within your Chipyard root directory. ``esp-tools`` is a fork of ``riscv-tools`` (formerly a collection of relevant software RISC-V tools) that was enhanced with additional non-standard vector instructions. However, due to the upstreaming of the equivalent RISC-V toolchains, ``esp-tools`` may not be up-to-date with the latest mainline version of the tools included in it. diff --git a/docs/Generators/index.rst b/docs/Generators/index.rst index 5aa097b6..5bb5d491 100644 --- a/docs/Generators/index.rst +++ b/docs/Generators/index.rst @@ -22,6 +22,7 @@ so changes to the generators themselves will automatically be used when building Rocket BOOM Hwacha + Gemmini IceNet TestChipIP SiFive-Generators diff --git a/docs/_static/images/gemmini-system.png b/docs/_static/images/gemmini-system.png new file mode 100644 index 0000000000000000000000000000000000000000..df44708fbec06198924698a47f0444ad1557a645 GIT binary patch literal 115294 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

p$;oMFEP{ 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 N?#oH#-h1Kxe*lrK0tEm7 literal 0 HcmV?d00001 diff --git a/docs/_static/images/gemmini-systolic-array.png b/docs/_static/images/gemmini-systolic-array.png new file mode 100644 index 0000000000000000000000000000000000000000..6586065a344ce13a39e44d417eff48acda34008f GIT binary patch literal 113148 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 b6|= Date: Sun, 8 Dec 2019 14:57:20 -0800 Subject: [PATCH 32/75] add example NIC configuration --- build.sbt | 2 +- .../example/src/main/scala/BoomConfigs.scala | 9 ++++++++- .../example/src/main/scala/ConfigMixins.scala | 17 +++++++++++++++++ .../example/src/main/scala/RocketConfigs.scala | 8 ++++++++ generators/example/src/main/scala/Top.scala | 11 +++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 2f27fdc1..6e30befd 100644 --- a/build.sbt +++ b/build.sbt @@ -123,7 +123,7 @@ lazy val testchipip = (project in file("generators/testchipip")) .settings(commonSettings) lazy val example = conditionalDependsOn(project in file("generators/example")) - .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities, sha3, gemmini) + .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities, sha3, gemmini, icenet) .settings(commonSettings) lazy val tracegen = conditionalDependsOn(project in file("generators/tracegen")) diff --git a/generators/example/src/main/scala/BoomConfigs.scala b/generators/example/src/main/scala/BoomConfigs.scala index e4198af8..3c144d00 100644 --- a/generators/example/src/main/scala/BoomConfigs.scala +++ b/generators/example/src/main/scala/BoomConfigs.scala @@ -67,4 +67,11 @@ class HwachaLargeBoomConfig extends Config( new boom.common.WithNBoomCores(1) ++ new freechips.rocketchip.system.BaseConfig) - +class LoopbackNICBoomConfig extends Config( + new WithIceNIC ++ + new WithLoopbackNICTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithLargeBooms ++ // 3-wide BOOM + new boom.common.WithNBoomCores(1) ++ + new freechips.rocketchip.system.BaseConfig) diff --git a/generators/example/src/main/scala/ConfigMixins.scala b/generators/example/src/main/scala/ConfigMixins.scala index 25104079..9454d9b5 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -18,6 +18,8 @@ import hwacha.{Hwacha} import sifive.blocks.devices.gpio._ +import icenet.{NICKey, NICConfig} + /** * TODO: Why do we need this? */ @@ -213,3 +215,18 @@ class WithControlCore extends Config((site, here, up) => { ) case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) }) + +class WithIceNIC(inBufFlits: Int = 1800, usePauser: Boolean = false) + extends Config((site, here, up) => { + case NICKey => NICConfig( + inBufFlits = inBufFlits, + usePauser = usePauser) +}) + +class WithLoopbackNICTop extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { + val top = Module(LazyModule(new TopWithIceNIC()(p)).module) + top.connectNicLoopback() + top + } +}) diff --git a/generators/example/src/main/scala/RocketConfigs.scala b/generators/example/src/main/scala/RocketConfigs.scala index 377b3995..d095980f 100644 --- a/generators/example/src/main/scala/RocketConfigs.scala +++ b/generators/example/src/main/scala/RocketConfigs.scala @@ -151,3 +151,11 @@ class InitZeroRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include end: InitZeroRocketConfig + +class LoopbackNICRocketConfig extends Config( + new WithIceNIC ++ + new WithLoopbackNICTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) diff --git a/generators/example/src/main/scala/Top.scala b/generators/example/src/main/scala/Top.scala index b7f1a500..586ec990 100644 --- a/generators/example/src/main/scala/Top.scala +++ b/generators/example/src/main/scala/Top.scala @@ -14,6 +14,8 @@ import utilities.{System, SystemModule} import sifive.blocks.devices.gpio._ +import icenet.{HasPeripheryIceNIC, HasPeripheryIceNICModuleImp} + // ------------------------------------ // BOOM and/or Rocket Top Level Systems // ------------------------------------ @@ -101,3 +103,12 @@ class TopWithInitZero(implicit p: Parameters) extends Top class TopWithInitZeroModuleImp(l: TopWithInitZero) extends TopModule(l) with HasPeripheryInitZeroModuleImp // DOC include end: TopWithInitZero + +class TopWithIceNIC(implicit p: Parameters) extends Top + with HasPeripheryIceNIC { + override lazy val module = new TopWithIceNICModule(this) +} + +class TopWithIceNICModule(outer: TopWithIceNIC) + extends TopModule(outer) + with HasPeripheryIceNICModuleImp From 1e0c5c5ac6641f1c42b167a6c577c3cb89c80a17 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Sun, 8 Dec 2019 22:12:20 -0800 Subject: [PATCH 33/75] add checksum offload support to NIC --- generators/example/src/main/scala/ConfigMixins.scala | 3 ++- generators/firechip/src/main/scala/TargetConfigs.scala | 3 ++- generators/icenet | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/generators/example/src/main/scala/ConfigMixins.scala b/generators/example/src/main/scala/ConfigMixins.scala index 9454d9b5..f06cd5f4 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -220,7 +220,8 @@ class WithIceNIC(inBufFlits: Int = 1800, usePauser: Boolean = false) extends Config((site, here, up) => { case NICKey => NICConfig( inBufFlits = inBufFlits, - usePauser = usePauser) + usePauser = usePauser, + checksumOffload = true) }) class WithLoopbackNICTop extends Config((site, here, up) => { diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index f7961c14..4cb0b990 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -52,7 +52,8 @@ class WithBlockDevice extends Config(new testchipip.WithBlockDevice) class WithNICKey extends Config((site, here, up) => { case NICKey => NICConfig( inBufFlits = 8192, - ctrlQueueDepth = 64) + ctrlQueueDepth = 64, + checksumOffload = true) }) class WithRocketL2TLBs(entries: Int) extends Config((site, here, up) => { diff --git a/generators/icenet b/generators/icenet index 77eb7eff..87b3bf5e 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit 77eb7eff2e6f39aa971f53f3c3ffbb27cc9bab2d +Subproject commit 87b3bf5e46da3db6f9a653fdd6786699c075bff3 From f71d976114eb60e8764f0a0168be8b339237bdd5 Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Sat, 16 Nov 2019 19:26:31 -0800 Subject: [PATCH 34/75] toolchains: Build libraries with medany code model This enables bare-metal programs to link against newlib and libgcc at addresses above 0x80000000. --- .circleci/config.yml | 50 +++++++++---------- scripts/build-toolchains.sh | 2 +- .../riscv-tools/riscv-gnu-toolchain-prebuilt | 2 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 75f13068..6514fdb8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,14 +31,14 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - run: name: Building riscv-tools toolchain command: | .circleci/build-toolchains.sh riscv-tools no_output_timeout: 120m - save_cache: - key: riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + key: riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} paths: - "/home/riscvuser/riscv-tools-install" install-esp-toolchain: @@ -55,14 +55,14 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - esp-tools-installed-v3-{{ checksum "../esp-tools.hash" }} + - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - run: name: Building esp-tools toolchain command: | .circleci/build-toolchains.sh esp-tools no_output_timeout: 120m - save_cache: - key: esp-tools-installed-v3-{{ checksum "../esp-tools.hash" }} + key: esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} paths: - "/home/riscvuser/esp-tools-install" install-verilator: @@ -105,7 +105,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - run: name: Build extra tests command: .circleci/build-extra-tests.sh @@ -131,7 +131,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -160,7 +160,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -189,7 +189,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -218,7 +218,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -247,7 +247,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -276,7 +276,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - esp-tools-installed-v3-{{ checksum "../esp-tools.hash" }} + - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -305,7 +305,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - esp-tools-installed-v2-{{ checksum "../esp-tools.hash" }} + - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -334,7 +334,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -363,7 +363,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -392,7 +392,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -418,7 +418,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} @@ -439,7 +439,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - example-{{ .Branch }}-{{ .Revision }} @@ -463,7 +463,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - boomrocketexample-{{ .Branch }}-{{ .Revision }} @@ -487,7 +487,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - boom-{{ .Branch }}-{{ .Revision }} @@ -511,7 +511,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - rocketchip-{{ .Branch }}-{{ .Revision }} @@ -535,7 +535,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - esp-tools-installed-v3-{{ checksum "../esp-tools.hash" }} + - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - restore_cache: keys: - hwacha-{{ .Branch }}-{{ .Revision }} @@ -559,7 +559,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - esp-tools-installed-v2-{{ checksum "../esp-tools.hash" }} + - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - restore_cache: keys: - gemmini-{{ .Branch }}-{{ .Revision }} @@ -583,7 +583,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - tracegen-{{ .Branch }}-{{ .Revision }} @@ -607,7 +607,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - firesim-{{ .Branch }}-{{ .Revision }} @@ -634,7 +634,7 @@ jobs: .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v3-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - restore_cache: keys: - fireboom-{{ .Branch }}-{{ .Revision }} diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index e858e452..9248a0ae 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -110,7 +110,7 @@ else esac; ) || die 'obsolete make version; need GNU make 4.x or later' module_prepare riscv-gnu-toolchain qemu - module_build riscv-gnu-toolchain --prefix="${RISCV}" + module_build riscv-gnu-toolchain --prefix="${RISCV}" --with-cmodel=medany echo '==> Building GNU/Linux toolchain' module_make riscv-gnu-toolchain linux fi diff --git a/toolchains/riscv-tools/riscv-gnu-toolchain-prebuilt b/toolchains/riscv-tools/riscv-gnu-toolchain-prebuilt index 5e32a015..543ff124 160000 --- a/toolchains/riscv-tools/riscv-gnu-toolchain-prebuilt +++ b/toolchains/riscv-tools/riscv-gnu-toolchain-prebuilt @@ -1 +1 @@ -Subproject commit 5e32a0157f91ebfb5c7ea7113fce28bf40016fa4 +Subproject commit 543ff1245e1c2071ea9d0252a622c9cece88b7f5 From 7059ac3f0fdec19b9f5d849550d3d28c0d877a18 Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Mon, 18 Nov 2019 01:42:25 -0800 Subject: [PATCH 35/75] toolchains: Add libgloss replacement --- .circleci/check-commit.sh | 2 +- .circleci/create-hash.sh | 3 ++- .gitmodules | 3 +++ scripts/build-toolchains.sh | 3 +++ scripts/init-submodules-no-riscv-tools.sh | 7 +++++-- toolchains/libgloss | 1 + 6 files changed, 15 insertions(+), 4 deletions(-) create mode 160000 toolchains/libgloss diff --git a/.circleci/check-commit.sh b/.circleci/check-commit.sh index ed3093fd..873b241e 100755 --- a/.circleci/check-commit.sh +++ b/.circleci/check-commit.sh @@ -75,7 +75,7 @@ dir="toolchains/riscv-tools" branches=("riscv") search -submodules=("qemu") +submodules=("qemu" "libgloss") dir="toolchains" branches=("master") search diff --git a/.circleci/create-hash.sh b/.circleci/create-hash.sh index 939eeb31..7a8915a5 100755 --- a/.circleci/create-hash.sh +++ b/.circleci/create-hash.sh @@ -15,7 +15,8 @@ cd $LOCAL_CHIPYARD_DIR # Use normalized output of git-submodule status as hashfile for tools in 'riscv-tools' 'esp-tools' ; do - git submodule status "toolchains/${tools}" "toolchains/qemu" | while read -r line ; do + git submodule status "toolchains/${tools}" 'toolchains/libgloss' 'toolchains/qemu' | + while read -r line ; do echo "${line#[!0-9a-f]}" done > "${HOME}/${tools}.hash" done diff --git a/.gitmodules b/.gitmodules index 7e6fca6f..d514a4e9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -65,6 +65,9 @@ [submodule "toolchains/esp-tools/riscv-tests"] path = toolchains/esp-tools/riscv-tests url = https://github.com/ucb-bar/esp-tests.git +[submodule "toolchains/libgloss"] + path = toolchains/libgloss + url = https://github.com/ucb-bar/libgloss-htif.git [submodule "vlsi/hammer"] path = vlsi/hammer url = https://github.com/ucb-bar/hammer.git diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index 9248a0ae..d5d181e7 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -125,6 +125,9 @@ CC= CXX= module_all riscv-pk --prefix="${RISCV}" --host=riscv64-unknown-elf module_all riscv-tests --prefix="${RISCV}/riscv64-unknown-elf" # Common tools (not in any particular toolchain dir) + +SRCDIR="$(pwd)/toolchains" module_all libgloss --prefix="${RISCV}/riscv64-unknown-elf" --host=riscv64-unknown-elf + SRCDIR="$(pwd)/toolchains" module_all qemu --prefix="${RISCV}" --target-list=riscv64-softmmu cd "$RDIR" diff --git a/scripts/init-submodules-no-riscv-tools.sh b/scripts/init-submodules-no-riscv-tools.sh index c61f8b3e..28f64c58 100755 --- a/scripts/init-submodules-no-riscv-tools.sh +++ b/scripts/init-submodules-no-riscv-tools.sh @@ -27,9 +27,10 @@ shift $((OPTIND - 1)) # Ignore toolchain submodules cd "$RDIR" -for name in toolchains/*/*/ ; do +for name in toolchains/*-tools/*/ ; do git config submodule."${name%/}".update none done +git config submodule.toolchains/libgloss.update none git config submodule.toolchains/qemu.update none # Don't automatically initialize generators with big submodules (e.g. linux source) @@ -42,10 +43,12 @@ git config submodule.vlsi/hammer-cadence-plugins.update none git config submodule.vlsi/hammer-synopsys-plugins.update none git config submodule.vlsi/hammer-mentor-plugins.update none git submodule update --init --recursive #--jobs 8 + # Un-ignore toolchain submodules -for name in toolchains/*/*/ ; do +for name in toolchains/*-tools/*/ ; do git config --unset submodule."${name%/}".update done +git config --unset submodule.toolchains/libgloss.update git config --unset submodule.toolchains/qemu.update git config --unset submodule.vlsi/hammer-cadence-plugins.update diff --git a/toolchains/libgloss b/toolchains/libgloss new file mode 160000 index 00000000..117b9997 --- /dev/null +++ b/toolchains/libgloss @@ -0,0 +1 @@ +Subproject commit 117b9997bf46b93687e52f8ea102bd89478de493 From f60e1a9c89f5c3ebd1f46798365427ff0a8c4110 Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Fri, 13 Dec 2019 15:03:20 -0800 Subject: [PATCH 36/75] tests: Migrate to newlib-nano and libgloss-htif This deprecates the monolithic syscalls.c environment in favor of a more structured board support package (BSP) based on newlib. --- tests/.gitignore | 1 + tests/Makefile | 17 +- tests/crt.S | 237 -------- tests/encoding.h | 1313 ------------------------------------------ tests/htif.ld | 1 + tests/libgloss.mk | 50 ++ tests/link.ld | 65 --- tests/nic-loopback.c | 2 +- tests/syscalls.c | 470 --------------- tests/util.h | 135 ----- 10 files changed, 66 insertions(+), 2225 deletions(-) delete mode 100644 tests/crt.S delete mode 100644 tests/encoding.h create mode 120000 tests/htif.ld create mode 100644 tests/libgloss.mk delete mode 100644 tests/link.ld delete mode 100644 tests/syscalls.c delete mode 100644 tests/util.h diff --git a/tests/.gitignore b/tests/.gitignore index 8efed223..b8212fd8 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,3 +1,4 @@ *.o *.riscv *.dump +libgloss/ diff --git a/tests/Makefile b/tests/Makefile index 80142ad7..6f247e70 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,12 +1,18 @@ GCC=riscv64-unknown-elf-gcc OBJDUMP=riscv64-unknown-elf-objdump -CFLAGS=-mcmodel=medany -std=gnu99 -O2 -fno-common -fno-builtin-printf -Wall -LDFLAGS=-static -nostdlib -nostartfiles -lgcc +CFLAGS= -std=gnu99 -O2 -fno-common -fno-builtin-printf -Wall +LDFLAGS= -static + +include libgloss.mk PROGRAMS = pwm blkdev accum charcount nic-loopback big-blkdev pingd +.DEFAULT_GOAL := default + +.PHONY: default default: $(addsuffix .riscv,$(PROGRAMS)) +.PHONY: dumps dumps: $(addsuffix .dump,$(PROGRAMS)) %.o: %.S @@ -15,11 +21,14 @@ dumps: $(addsuffix .dump,$(PROGRAMS)) %.o: %.c mmio.h $(GCC) $(CFLAGS) -c $< -o $@ -%.riscv: %.o crt.o syscalls.o link.ld - $(GCC) -T link.ld $(LDFLAGS) $< crt.o syscalls.o -o $@ +%.riscv: %.o $(libgloss) + $(GCC) $(LDFLAGS) $< -o $@ %.dump: %.riscv $(OBJDUMP) -D $< > $@ + +.PHONY: clean clean: rm -f *.riscv *.o *.dump + $(if $(libgloss),rm -rf $(libgloss_builddir)/) diff --git a/tests/crt.S b/tests/crt.S deleted file mode 100644 index d75e81e0..00000000 --- a/tests/crt.S +++ /dev/null @@ -1,237 +0,0 @@ -# See LICENSE for license details. - -#include "encoding.h" - -#if __riscv_xlen == 64 -# define LREG ld -# define SREG sd -# define REGBYTES 8 -#else -# define LREG lw -# define SREG sw -# define REGBYTES 4 -#endif - - .section ".text.init" - .globl _start -_start: - li x1, 0 - li x2, 0 - li x3, 0 - li x4, 0 - li x5, 0 - li x6, 0 - li x7, 0 - li x8, 0 - li x9, 0 - li x10,0 - li x11,0 - li x12,0 - li x13,0 - li x14,0 - li x15,0 - li x16,0 - li x17,0 - li x18,0 - li x19,0 - li x20,0 - li x21,0 - li x22,0 - li x23,0 - li x24,0 - li x25,0 - li x26,0 - li x27,0 - li x28,0 - li x29,0 - li x30,0 - li x31,0 - - # enable FPU and accelerator if present - li t0, MSTATUS_FS | MSTATUS_XS - csrs mstatus, t0 - - # make sure XLEN agrees with compilation choice - li t0, 1 - slli t0, t0, 31 -#if __riscv_xlen == 64 - bgez t0, 1f -#else - bltz t0, 1f -#endif -2: - li a0, 1 - sw a0, tohost, t0 - j 2b -1: - -#ifdef __riscv_flen - # initialize FPU if we have one - la t0, 1f - csrw mtvec, t0 - - fssr x0 - fmv.s.x f0, x0 - fmv.s.x f1, x0 - fmv.s.x f2, x0 - fmv.s.x f3, x0 - fmv.s.x f4, x0 - fmv.s.x f5, x0 - fmv.s.x f6, x0 - fmv.s.x f7, x0 - fmv.s.x f8, x0 - fmv.s.x f9, x0 - fmv.s.x f10,x0 - fmv.s.x f11,x0 - fmv.s.x f12,x0 - fmv.s.x f13,x0 - fmv.s.x f14,x0 - fmv.s.x f15,x0 - fmv.s.x f16,x0 - fmv.s.x f17,x0 - fmv.s.x f18,x0 - fmv.s.x f19,x0 - fmv.s.x f20,x0 - fmv.s.x f21,x0 - fmv.s.x f22,x0 - fmv.s.x f23,x0 - fmv.s.x f24,x0 - fmv.s.x f25,x0 - fmv.s.x f26,x0 - fmv.s.x f27,x0 - fmv.s.x f28,x0 - fmv.s.x f29,x0 - fmv.s.x f30,x0 - fmv.s.x f31,x0 -1: -#endif - - # initialize trap vector - la t0, trap_entry - csrw mtvec, t0 - - # initialize global pointer -.option push -.option norelax - la gp, __global_pointer$ -.option pop - - la tp, _end + 63 - and tp, tp, -64 - - # get core id - csrr a0, mhartid - # for now, assume only 1 core - li a1, 1 -1:bgeu a0, a1, 1b - - # give each core 128KB of stack + TLS -#define STKSHIFT 17 - sll a2, a0, STKSHIFT - add tp, tp, a2 - add sp, a0, 1 - sll sp, sp, STKSHIFT - add sp, sp, tp - - j _init - - .align 2 -trap_entry: - addi sp, sp, -272 - - SREG x1, 1*REGBYTES(sp) - SREG x2, 2*REGBYTES(sp) - SREG x3, 3*REGBYTES(sp) - SREG x4, 4*REGBYTES(sp) - SREG x5, 5*REGBYTES(sp) - SREG x6, 6*REGBYTES(sp) - SREG x7, 7*REGBYTES(sp) - SREG x8, 8*REGBYTES(sp) - SREG x9, 9*REGBYTES(sp) - SREG x10, 10*REGBYTES(sp) - SREG x11, 11*REGBYTES(sp) - SREG x12, 12*REGBYTES(sp) - SREG x13, 13*REGBYTES(sp) - SREG x14, 14*REGBYTES(sp) - SREG x15, 15*REGBYTES(sp) - SREG x16, 16*REGBYTES(sp) - SREG x17, 17*REGBYTES(sp) - SREG x18, 18*REGBYTES(sp) - SREG x19, 19*REGBYTES(sp) - SREG x20, 20*REGBYTES(sp) - SREG x21, 21*REGBYTES(sp) - SREG x22, 22*REGBYTES(sp) - SREG x23, 23*REGBYTES(sp) - SREG x24, 24*REGBYTES(sp) - SREG x25, 25*REGBYTES(sp) - SREG x26, 26*REGBYTES(sp) - SREG x27, 27*REGBYTES(sp) - SREG x28, 28*REGBYTES(sp) - SREG x29, 29*REGBYTES(sp) - SREG x30, 30*REGBYTES(sp) - SREG x31, 31*REGBYTES(sp) - - csrr a0, mcause - csrr a1, mepc - mv a2, sp - jal handle_trap - csrw mepc, a0 - - # Remain in M-mode after eret - li t0, MSTATUS_MPP - csrs mstatus, t0 - - LREG x1, 1*REGBYTES(sp) - LREG x2, 2*REGBYTES(sp) - LREG x3, 3*REGBYTES(sp) - LREG x4, 4*REGBYTES(sp) - LREG x5, 5*REGBYTES(sp) - LREG x6, 6*REGBYTES(sp) - LREG x7, 7*REGBYTES(sp) - LREG x8, 8*REGBYTES(sp) - LREG x9, 9*REGBYTES(sp) - LREG x10, 10*REGBYTES(sp) - LREG x11, 11*REGBYTES(sp) - LREG x12, 12*REGBYTES(sp) - LREG x13, 13*REGBYTES(sp) - LREG x14, 14*REGBYTES(sp) - LREG x15, 15*REGBYTES(sp) - LREG x16, 16*REGBYTES(sp) - LREG x17, 17*REGBYTES(sp) - LREG x18, 18*REGBYTES(sp) - LREG x19, 19*REGBYTES(sp) - LREG x20, 20*REGBYTES(sp) - LREG x21, 21*REGBYTES(sp) - LREG x22, 22*REGBYTES(sp) - LREG x23, 23*REGBYTES(sp) - LREG x24, 24*REGBYTES(sp) - LREG x25, 25*REGBYTES(sp) - LREG x26, 26*REGBYTES(sp) - LREG x27, 27*REGBYTES(sp) - LREG x28, 28*REGBYTES(sp) - LREG x29, 29*REGBYTES(sp) - LREG x30, 30*REGBYTES(sp) - LREG x31, 31*REGBYTES(sp) - - addi sp, sp, 272 - mret - -.section ".tdata.begin" -.globl _tdata_begin -_tdata_begin: - -.section ".tdata.end" -.globl _tdata_end -_tdata_end: - -.section ".tbss.end" -.globl _tbss_end -_tbss_end: - -.section ".tohost","aw",@progbits -.align 6 -.globl tohost -tohost: .dword 0 -.align 6 -.globl fromhost -fromhost: .dword 0 diff --git a/tests/encoding.h b/tests/encoding.h deleted file mode 100644 index 35e0f9fe..00000000 --- a/tests/encoding.h +++ /dev/null @@ -1,1313 +0,0 @@ -// See LICENSE for license details. - -#ifndef RISCV_CSR_ENCODING_H -#define RISCV_CSR_ENCODING_H - -#define MSTATUS_UIE 0x00000001 -#define MSTATUS_SIE 0x00000002 -#define MSTATUS_HIE 0x00000004 -#define MSTATUS_MIE 0x00000008 -#define MSTATUS_UPIE 0x00000010 -#define MSTATUS_SPIE 0x00000020 -#define MSTATUS_HPIE 0x00000040 -#define MSTATUS_MPIE 0x00000080 -#define MSTATUS_SPP 0x00000100 -#define MSTATUS_HPP 0x00000600 -#define MSTATUS_MPP 0x00001800 -#define MSTATUS_FS 0x00006000 -#define MSTATUS_XS 0x00018000 -#define MSTATUS_MPRV 0x00020000 -#define MSTATUS_PUM 0x00040000 -#define MSTATUS_MXR 0x00080000 -#define MSTATUS_VM 0x1F000000 -#define MSTATUS32_SD 0x80000000 -#define MSTATUS64_SD 0x8000000000000000 - -#define SSTATUS_UIE 0x00000001 -#define SSTATUS_SIE 0x00000002 -#define SSTATUS_UPIE 0x00000010 -#define SSTATUS_SPIE 0x00000020 -#define SSTATUS_SPP 0x00000100 -#define SSTATUS_FS 0x00006000 -#define SSTATUS_XS 0x00018000 -#define SSTATUS_PUM 0x00040000 -#define SSTATUS32_SD 0x80000000 -#define SSTATUS64_SD 0x8000000000000000 - -#define DCSR_XDEBUGVER (3U<<30) -#define DCSR_NDRESET (1<<29) -#define DCSR_FULLRESET (1<<28) -#define DCSR_EBREAKM (1<<15) -#define DCSR_EBREAKH (1<<14) -#define DCSR_EBREAKS (1<<13) -#define DCSR_EBREAKU (1<<12) -#define DCSR_STOPCYCLE (1<<10) -#define DCSR_STOPTIME (1<<9) -#define DCSR_CAUSE (7<<6) -#define DCSR_DEBUGINT (1<<5) -#define DCSR_HALT (1<<3) -#define DCSR_STEP (1<<2) -#define DCSR_PRV (3<<0) - -#define DCSR_CAUSE_NONE 0 -#define DCSR_CAUSE_SWBP 1 -#define DCSR_CAUSE_HWBP 2 -#define DCSR_CAUSE_DEBUGINT 3 -#define DCSR_CAUSE_STEP 4 -#define DCSR_CAUSE_HALT 5 - -#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) -#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) -#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) - -#define MCONTROL_SELECT (1<<19) -#define MCONTROL_TIMING (1<<18) -#define MCONTROL_ACTION (0x3f<<12) -#define MCONTROL_CHAIN (1<<11) -#define MCONTROL_MATCH (0xf<<7) -#define MCONTROL_M (1<<6) -#define MCONTROL_H (1<<5) -#define MCONTROL_S (1<<4) -#define MCONTROL_U (1<<3) -#define MCONTROL_EXECUTE (1<<2) -#define MCONTROL_STORE (1<<1) -#define MCONTROL_LOAD (1<<0) - -#define MCONTROL_TYPE_NONE 0 -#define MCONTROL_TYPE_MATCH 2 - -#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 -#define MCONTROL_ACTION_DEBUG_MODE 1 -#define MCONTROL_ACTION_TRACE_START 2 -#define MCONTROL_ACTION_TRACE_STOP 3 -#define MCONTROL_ACTION_TRACE_EMIT 4 - -#define MCONTROL_MATCH_EQUAL 0 -#define MCONTROL_MATCH_NAPOT 1 -#define MCONTROL_MATCH_GE 2 -#define MCONTROL_MATCH_LT 3 -#define MCONTROL_MATCH_MASK_LOW 4 -#define MCONTROL_MATCH_MASK_HIGH 5 - -#define MIP_SSIP (1 << IRQ_S_SOFT) -#define MIP_HSIP (1 << IRQ_H_SOFT) -#define MIP_MSIP (1 << IRQ_M_SOFT) -#define MIP_STIP (1 << IRQ_S_TIMER) -#define MIP_HTIP (1 << IRQ_H_TIMER) -#define MIP_MTIP (1 << IRQ_M_TIMER) -#define MIP_SEIP (1 << IRQ_S_EXT) -#define MIP_HEIP (1 << IRQ_H_EXT) -#define MIP_MEIP (1 << IRQ_M_EXT) - -#define SIP_SSIP MIP_SSIP -#define SIP_STIP MIP_STIP - -#define PRV_U 0 -#define PRV_S 1 -#define PRV_H 2 -#define PRV_M 3 - -#define VM_MBARE 0 -#define VM_MBB 1 -#define VM_MBBID 2 -#define VM_SV32 8 -#define VM_SV39 9 -#define VM_SV48 10 - -#define IRQ_S_SOFT 1 -#define IRQ_H_SOFT 2 -#define IRQ_M_SOFT 3 -#define IRQ_S_TIMER 5 -#define IRQ_H_TIMER 6 -#define IRQ_M_TIMER 7 -#define IRQ_S_EXT 9 -#define IRQ_H_EXT 10 -#define IRQ_M_EXT 11 -#define IRQ_COP 12 -#define IRQ_HOST 13 - -#define DEFAULT_RSTVEC 0x00001000 -#define DEFAULT_NMIVEC 0x00001004 -#define DEFAULT_MTVEC 0x00001010 -#define CONFIG_STRING_ADDR 0x0000100C -#define EXT_IO_BASE 0x40000000 -#define DRAM_BASE 0x80000000 - -// page table entry (PTE) fields -#define PTE_V 0x001 // Valid -#define PTE_R 0x002 // Read -#define PTE_W 0x004 // Write -#define PTE_X 0x008 // Execute -#define PTE_U 0x010 // User -#define PTE_G 0x020 // Global -#define PTE_A 0x040 // Accessed -#define PTE_D 0x080 // Dirty -#define PTE_SOFT 0x300 // Reserved for Software - -#define PTE_PPN_SHIFT 10 - -#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) - -#ifdef __riscv - -#ifdef __riscv64 -# define MSTATUS_SD MSTATUS64_SD -# define SSTATUS_SD SSTATUS64_SD -# define RISCV_PGLEVEL_BITS 9 -#else -# define MSTATUS_SD MSTATUS32_SD -# define SSTATUS_SD SSTATUS32_SD -# define RISCV_PGLEVEL_BITS 10 -#endif -#define RISCV_PGSHIFT 12 -#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) - -#ifndef __ASSEMBLER__ - -#ifdef __GNUC__ - -#define read_csr(reg) ({ unsigned long __tmp; \ - asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ - __tmp; }) - -#define write_csr(reg, val) ({ \ - if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ - asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ - else \ - asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) - -#define swap_csr(reg, val) ({ unsigned long __tmp; \ - if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ - asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \ - else \ - asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ - __tmp; }) - -#define set_csr(reg, bit) ({ unsigned long __tmp; \ - if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ - asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ - else \ - asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ - __tmp; }) - -#define clear_csr(reg, bit) ({ unsigned long __tmp; \ - if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ - asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ - else \ - asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ - __tmp; }) - -#define rdtime() read_csr(time) -#define rdcycle() read_csr(cycle) -#define rdinstret() read_csr(instret) - -#endif - -#endif - -#endif - -#endif -/* Automatically generated by parse-opcodes */ -#ifndef RISCV_ENCODING_H -#define RISCV_ENCODING_H -#define MATCH_BEQ 0x63 -#define MASK_BEQ 0x707f -#define MATCH_BNE 0x1063 -#define MASK_BNE 0x707f -#define MATCH_BLT 0x4063 -#define MASK_BLT 0x707f -#define MATCH_BGE 0x5063 -#define MASK_BGE 0x707f -#define MATCH_BLTU 0x6063 -#define MASK_BLTU 0x707f -#define MATCH_BGEU 0x7063 -#define MASK_BGEU 0x707f -#define MATCH_JALR 0x67 -#define MASK_JALR 0x707f -#define MATCH_JAL 0x6f -#define MASK_JAL 0x7f -#define MATCH_LUI 0x37 -#define MASK_LUI 0x7f -#define MATCH_AUIPC 0x17 -#define MASK_AUIPC 0x7f -#define MATCH_ADDI 0x13 -#define MASK_ADDI 0x707f -#define MATCH_SLLI 0x1013 -#define MASK_SLLI 0xfc00707f -#define MATCH_SLTI 0x2013 -#define MASK_SLTI 0x707f -#define MATCH_SLTIU 0x3013 -#define MASK_SLTIU 0x707f -#define MATCH_XORI 0x4013 -#define MASK_XORI 0x707f -#define MATCH_SRLI 0x5013 -#define MASK_SRLI 0xfc00707f -#define MATCH_SRAI 0x40005013 -#define MASK_SRAI 0xfc00707f -#define MATCH_ORI 0x6013 -#define MASK_ORI 0x707f -#define MATCH_ANDI 0x7013 -#define MASK_ANDI 0x707f -#define MATCH_ADD 0x33 -#define MASK_ADD 0xfe00707f -#define MATCH_SUB 0x40000033 -#define MASK_SUB 0xfe00707f -#define MATCH_SLL 0x1033 -#define MASK_SLL 0xfe00707f -#define MATCH_SLT 0x2033 -#define MASK_SLT 0xfe00707f -#define MATCH_SLTU 0x3033 -#define MASK_SLTU 0xfe00707f -#define MATCH_XOR 0x4033 -#define MASK_XOR 0xfe00707f -#define MATCH_SRL 0x5033 -#define MASK_SRL 0xfe00707f -#define MATCH_SRA 0x40005033 -#define MASK_SRA 0xfe00707f -#define MATCH_OR 0x6033 -#define MASK_OR 0xfe00707f -#define MATCH_AND 0x7033 -#define MASK_AND 0xfe00707f -#define MATCH_ADDIW 0x1b -#define MASK_ADDIW 0x707f -#define MATCH_SLLIW 0x101b -#define MASK_SLLIW 0xfe00707f -#define MATCH_SRLIW 0x501b -#define MASK_SRLIW 0xfe00707f -#define MATCH_SRAIW 0x4000501b -#define MASK_SRAIW 0xfe00707f -#define MATCH_ADDW 0x3b -#define MASK_ADDW 0xfe00707f -#define MATCH_SUBW 0x4000003b -#define MASK_SUBW 0xfe00707f -#define MATCH_SLLW 0x103b -#define MASK_SLLW 0xfe00707f -#define MATCH_SRLW 0x503b -#define MASK_SRLW 0xfe00707f -#define MATCH_SRAW 0x4000503b -#define MASK_SRAW 0xfe00707f -#define MATCH_LB 0x3 -#define MASK_LB 0x707f -#define MATCH_LH 0x1003 -#define MASK_LH 0x707f -#define MATCH_LW 0x2003 -#define MASK_LW 0x707f -#define MATCH_LD 0x3003 -#define MASK_LD 0x707f -#define MATCH_LBU 0x4003 -#define MASK_LBU 0x707f -#define MATCH_LHU 0x5003 -#define MASK_LHU 0x707f -#define MATCH_LWU 0x6003 -#define MASK_LWU 0x707f -#define MATCH_SB 0x23 -#define MASK_SB 0x707f -#define MATCH_SH 0x1023 -#define MASK_SH 0x707f -#define MATCH_SW 0x2023 -#define MASK_SW 0x707f -#define MATCH_SD 0x3023 -#define MASK_SD 0x707f -#define MATCH_FENCE 0xf -#define MASK_FENCE 0x707f -#define MATCH_FENCE_I 0x100f -#define MASK_FENCE_I 0x707f -#define MATCH_MUL 0x2000033 -#define MASK_MUL 0xfe00707f -#define MATCH_MULH 0x2001033 -#define MASK_MULH 0xfe00707f -#define MATCH_MULHSU 0x2002033 -#define MASK_MULHSU 0xfe00707f -#define MATCH_MULHU 0x2003033 -#define MASK_MULHU 0xfe00707f -#define MATCH_DIV 0x2004033 -#define MASK_DIV 0xfe00707f -#define MATCH_DIVU 0x2005033 -#define MASK_DIVU 0xfe00707f -#define MATCH_REM 0x2006033 -#define MASK_REM 0xfe00707f -#define MATCH_REMU 0x2007033 -#define MASK_REMU 0xfe00707f -#define MATCH_MULW 0x200003b -#define MASK_MULW 0xfe00707f -#define MATCH_DIVW 0x200403b -#define MASK_DIVW 0xfe00707f -#define MATCH_DIVUW 0x200503b -#define MASK_DIVUW 0xfe00707f -#define MATCH_REMW 0x200603b -#define MASK_REMW 0xfe00707f -#define MATCH_REMUW 0x200703b -#define MASK_REMUW 0xfe00707f -#define MATCH_AMOADD_W 0x202f -#define MASK_AMOADD_W 0xf800707f -#define MATCH_AMOXOR_W 0x2000202f -#define MASK_AMOXOR_W 0xf800707f -#define MATCH_AMOOR_W 0x4000202f -#define MASK_AMOOR_W 0xf800707f -#define MATCH_AMOAND_W 0x6000202f -#define MASK_AMOAND_W 0xf800707f -#define MATCH_AMOMIN_W 0x8000202f -#define MASK_AMOMIN_W 0xf800707f -#define MATCH_AMOMAX_W 0xa000202f -#define MASK_AMOMAX_W 0xf800707f -#define MATCH_AMOMINU_W 0xc000202f -#define MASK_AMOMINU_W 0xf800707f -#define MATCH_AMOMAXU_W 0xe000202f -#define MASK_AMOMAXU_W 0xf800707f -#define MATCH_AMOSWAP_W 0x800202f -#define MASK_AMOSWAP_W 0xf800707f -#define MATCH_LR_W 0x1000202f -#define MASK_LR_W 0xf9f0707f -#define MATCH_SC_W 0x1800202f -#define MASK_SC_W 0xf800707f -#define MATCH_AMOADD_D 0x302f -#define MASK_AMOADD_D 0xf800707f -#define MATCH_AMOXOR_D 0x2000302f -#define MASK_AMOXOR_D 0xf800707f -#define MATCH_AMOOR_D 0x4000302f -#define MASK_AMOOR_D 0xf800707f -#define MATCH_AMOAND_D 0x6000302f -#define MASK_AMOAND_D 0xf800707f -#define MATCH_AMOMIN_D 0x8000302f -#define MASK_AMOMIN_D 0xf800707f -#define MATCH_AMOMAX_D 0xa000302f -#define MASK_AMOMAX_D 0xf800707f -#define MATCH_AMOMINU_D 0xc000302f -#define MASK_AMOMINU_D 0xf800707f -#define MATCH_AMOMAXU_D 0xe000302f -#define MASK_AMOMAXU_D 0xf800707f -#define MATCH_AMOSWAP_D 0x800302f -#define MASK_AMOSWAP_D 0xf800707f -#define MATCH_LR_D 0x1000302f -#define MASK_LR_D 0xf9f0707f -#define MATCH_SC_D 0x1800302f -#define MASK_SC_D 0xf800707f -#define MATCH_ECALL 0x73 -#define MASK_ECALL 0xffffffff -#define MATCH_EBREAK 0x100073 -#define MASK_EBREAK 0xffffffff -#define MATCH_URET 0x200073 -#define MASK_URET 0xffffffff -#define MATCH_SRET 0x10200073 -#define MASK_SRET 0xffffffff -#define MATCH_HRET 0x20200073 -#define MASK_HRET 0xffffffff -#define MATCH_MRET 0x30200073 -#define MASK_MRET 0xffffffff -#define MATCH_DRET 0x7b200073 -#define MASK_DRET 0xffffffff -#define MATCH_SFENCE_VM 0x10400073 -#define MASK_SFENCE_VM 0xfff07fff -#define MATCH_WFI 0x10500073 -#define MASK_WFI 0xffffffff -#define MATCH_CSRRW 0x1073 -#define MASK_CSRRW 0x707f -#define MATCH_CSRRS 0x2073 -#define MASK_CSRRS 0x707f -#define MATCH_CSRRC 0x3073 -#define MASK_CSRRC 0x707f -#define MATCH_CSRRWI 0x5073 -#define MASK_CSRRWI 0x707f -#define MATCH_CSRRSI 0x6073 -#define MASK_CSRRSI 0x707f -#define MATCH_CSRRCI 0x7073 -#define MASK_CSRRCI 0x707f -#define MATCH_FADD_S 0x53 -#define MASK_FADD_S 0xfe00007f -#define MATCH_FSUB_S 0x8000053 -#define MASK_FSUB_S 0xfe00007f -#define MATCH_FMUL_S 0x10000053 -#define MASK_FMUL_S 0xfe00007f -#define MATCH_FDIV_S 0x18000053 -#define MASK_FDIV_S 0xfe00007f -#define MATCH_FSGNJ_S 0x20000053 -#define MASK_FSGNJ_S 0xfe00707f -#define MATCH_FSGNJN_S 0x20001053 -#define MASK_FSGNJN_S 0xfe00707f -#define MATCH_FSGNJX_S 0x20002053 -#define MASK_FSGNJX_S 0xfe00707f -#define MATCH_FMIN_S 0x28000053 -#define MASK_FMIN_S 0xfe00707f -#define MATCH_FMAX_S 0x28001053 -#define MASK_FMAX_S 0xfe00707f -#define MATCH_FSQRT_S 0x58000053 -#define MASK_FSQRT_S 0xfff0007f -#define MATCH_FADD_D 0x2000053 -#define MASK_FADD_D 0xfe00007f -#define MATCH_FSUB_D 0xa000053 -#define MASK_FSUB_D 0xfe00007f -#define MATCH_FMUL_D 0x12000053 -#define MASK_FMUL_D 0xfe00007f -#define MATCH_FDIV_D 0x1a000053 -#define MASK_FDIV_D 0xfe00007f -#define MATCH_FSGNJ_D 0x22000053 -#define MASK_FSGNJ_D 0xfe00707f -#define MATCH_FSGNJN_D 0x22001053 -#define MASK_FSGNJN_D 0xfe00707f -#define MATCH_FSGNJX_D 0x22002053 -#define MASK_FSGNJX_D 0xfe00707f -#define MATCH_FMIN_D 0x2a000053 -#define MASK_FMIN_D 0xfe00707f -#define MATCH_FMAX_D 0x2a001053 -#define MASK_FMAX_D 0xfe00707f -#define MATCH_FCVT_S_D 0x40100053 -#define MASK_FCVT_S_D 0xfff0007f -#define MATCH_FCVT_D_S 0x42000053 -#define MASK_FCVT_D_S 0xfff0007f -#define MATCH_FSQRT_D 0x5a000053 -#define MASK_FSQRT_D 0xfff0007f -#define MATCH_FLE_S 0xa0000053 -#define MASK_FLE_S 0xfe00707f -#define MATCH_FLT_S 0xa0001053 -#define MASK_FLT_S 0xfe00707f -#define MATCH_FEQ_S 0xa0002053 -#define MASK_FEQ_S 0xfe00707f -#define MATCH_FLE_D 0xa2000053 -#define MASK_FLE_D 0xfe00707f -#define MATCH_FLT_D 0xa2001053 -#define MASK_FLT_D 0xfe00707f -#define MATCH_FEQ_D 0xa2002053 -#define MASK_FEQ_D 0xfe00707f -#define MATCH_FCVT_W_S 0xc0000053 -#define MASK_FCVT_W_S 0xfff0007f -#define MATCH_FCVT_WU_S 0xc0100053 -#define MASK_FCVT_WU_S 0xfff0007f -#define MATCH_FCVT_L_S 0xc0200053 -#define MASK_FCVT_L_S 0xfff0007f -#define MATCH_FCVT_LU_S 0xc0300053 -#define MASK_FCVT_LU_S 0xfff0007f -#define MATCH_FMV_X_S 0xe0000053 -#define MASK_FMV_X_S 0xfff0707f -#define MATCH_FCLASS_S 0xe0001053 -#define MASK_FCLASS_S 0xfff0707f -#define MATCH_FCVT_W_D 0xc2000053 -#define MASK_FCVT_W_D 0xfff0007f -#define MATCH_FCVT_WU_D 0xc2100053 -#define MASK_FCVT_WU_D 0xfff0007f -#define MATCH_FCVT_L_D 0xc2200053 -#define MASK_FCVT_L_D 0xfff0007f -#define MATCH_FCVT_LU_D 0xc2300053 -#define MASK_FCVT_LU_D 0xfff0007f -#define MATCH_FMV_X_D 0xe2000053 -#define MASK_FMV_X_D 0xfff0707f -#define MATCH_FCLASS_D 0xe2001053 -#define MASK_FCLASS_D 0xfff0707f -#define MATCH_FCVT_S_W 0xd0000053 -#define MASK_FCVT_S_W 0xfff0007f -#define MATCH_FCVT_S_WU 0xd0100053 -#define MASK_FCVT_S_WU 0xfff0007f -#define MATCH_FCVT_S_L 0xd0200053 -#define MASK_FCVT_S_L 0xfff0007f -#define MATCH_FCVT_S_LU 0xd0300053 -#define MASK_FCVT_S_LU 0xfff0007f -#define MATCH_FMV_S_X 0xf0000053 -#define MASK_FMV_S_X 0xfff0707f -#define MATCH_FCVT_D_W 0xd2000053 -#define MASK_FCVT_D_W 0xfff0007f -#define MATCH_FCVT_D_WU 0xd2100053 -#define MASK_FCVT_D_WU 0xfff0007f -#define MATCH_FCVT_D_L 0xd2200053 -#define MASK_FCVT_D_L 0xfff0007f -#define MATCH_FCVT_D_LU 0xd2300053 -#define MASK_FCVT_D_LU 0xfff0007f -#define MATCH_FMV_D_X 0xf2000053 -#define MASK_FMV_D_X 0xfff0707f -#define MATCH_FLW 0x2007 -#define MASK_FLW 0x707f -#define MATCH_FLD 0x3007 -#define MASK_FLD 0x707f -#define MATCH_FSW 0x2027 -#define MASK_FSW 0x707f -#define MATCH_FSD 0x3027 -#define MASK_FSD 0x707f -#define MATCH_FMADD_S 0x43 -#define MASK_FMADD_S 0x600007f -#define MATCH_FMSUB_S 0x47 -#define MASK_FMSUB_S 0x600007f -#define MATCH_FNMSUB_S 0x4b -#define MASK_FNMSUB_S 0x600007f -#define MATCH_FNMADD_S 0x4f -#define MASK_FNMADD_S 0x600007f -#define MATCH_FMADD_D 0x2000043 -#define MASK_FMADD_D 0x600007f -#define MATCH_FMSUB_D 0x2000047 -#define MASK_FMSUB_D 0x600007f -#define MATCH_FNMSUB_D 0x200004b -#define MASK_FNMSUB_D 0x600007f -#define MATCH_FNMADD_D 0x200004f -#define MASK_FNMADD_D 0x600007f -#define MATCH_C_NOP 0x1 -#define MASK_C_NOP 0xffff -#define MATCH_C_ADDI16SP 0x6101 -#define MASK_C_ADDI16SP 0xef83 -#define MATCH_C_JR 0x8002 -#define MASK_C_JR 0xf07f -#define MATCH_C_JALR 0x9002 -#define MASK_C_JALR 0xf07f -#define MATCH_C_EBREAK 0x9002 -#define MASK_C_EBREAK 0xffff -#define MATCH_C_LD 0x6000 -#define MASK_C_LD 0xe003 -#define MATCH_C_SD 0xe000 -#define MASK_C_SD 0xe003 -#define MATCH_C_ADDIW 0x2001 -#define MASK_C_ADDIW 0xe003 -#define MATCH_C_LDSP 0x6002 -#define MASK_C_LDSP 0xe003 -#define MATCH_C_SDSP 0xe002 -#define MASK_C_SDSP 0xe003 -#define MATCH_C_ADDI4SPN 0x0 -#define MASK_C_ADDI4SPN 0xe003 -#define MATCH_C_FLD 0x2000 -#define MASK_C_FLD 0xe003 -#define MATCH_C_LW 0x4000 -#define MASK_C_LW 0xe003 -#define MATCH_C_FLW 0x6000 -#define MASK_C_FLW 0xe003 -#define MATCH_C_FSD 0xa000 -#define MASK_C_FSD 0xe003 -#define MATCH_C_SW 0xc000 -#define MASK_C_SW 0xe003 -#define MATCH_C_FSW 0xe000 -#define MASK_C_FSW 0xe003 -#define MATCH_C_ADDI 0x1 -#define MASK_C_ADDI 0xe003 -#define MATCH_C_JAL 0x2001 -#define MASK_C_JAL 0xe003 -#define MATCH_C_LI 0x4001 -#define MASK_C_LI 0xe003 -#define MATCH_C_LUI 0x6001 -#define MASK_C_LUI 0xe003 -#define MATCH_C_SRLI 0x8001 -#define MASK_C_SRLI 0xec03 -#define MATCH_C_SRAI 0x8401 -#define MASK_C_SRAI 0xec03 -#define MATCH_C_ANDI 0x8801 -#define MASK_C_ANDI 0xec03 -#define MATCH_C_SUB 0x8c01 -#define MASK_C_SUB 0xfc63 -#define MATCH_C_XOR 0x8c21 -#define MASK_C_XOR 0xfc63 -#define MATCH_C_OR 0x8c41 -#define MASK_C_OR 0xfc63 -#define MATCH_C_AND 0x8c61 -#define MASK_C_AND 0xfc63 -#define MATCH_C_SUBW 0x9c01 -#define MASK_C_SUBW 0xfc63 -#define MATCH_C_ADDW 0x9c21 -#define MASK_C_ADDW 0xfc63 -#define MATCH_C_J 0xa001 -#define MASK_C_J 0xe003 -#define MATCH_C_BEQZ 0xc001 -#define MASK_C_BEQZ 0xe003 -#define MATCH_C_BNEZ 0xe001 -#define MASK_C_BNEZ 0xe003 -#define MATCH_C_SLLI 0x2 -#define MASK_C_SLLI 0xe003 -#define MATCH_C_FLDSP 0x2002 -#define MASK_C_FLDSP 0xe003 -#define MATCH_C_LWSP 0x4002 -#define MASK_C_LWSP 0xe003 -#define MATCH_C_FLWSP 0x6002 -#define MASK_C_FLWSP 0xe003 -#define MATCH_C_MV 0x8002 -#define MASK_C_MV 0xf003 -#define MATCH_C_ADD 0x9002 -#define MASK_C_ADD 0xf003 -#define MATCH_C_FSDSP 0xa002 -#define MASK_C_FSDSP 0xe003 -#define MATCH_C_SWSP 0xc002 -#define MASK_C_SWSP 0xe003 -#define MATCH_C_FSWSP 0xe002 -#define MASK_C_FSWSP 0xe003 -#define MATCH_CUSTOM0 0xb -#define MASK_CUSTOM0 0x707f -#define MATCH_CUSTOM0_RS1 0x200b -#define MASK_CUSTOM0_RS1 0x707f -#define MATCH_CUSTOM0_RS1_RS2 0x300b -#define MASK_CUSTOM0_RS1_RS2 0x707f -#define MATCH_CUSTOM0_RD 0x400b -#define MASK_CUSTOM0_RD 0x707f -#define MATCH_CUSTOM0_RD_RS1 0x600b -#define MASK_CUSTOM0_RD_RS1 0x707f -#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b -#define MASK_CUSTOM0_RD_RS1_RS2 0x707f -#define MATCH_CUSTOM1 0x2b -#define MASK_CUSTOM1 0x707f -#define MATCH_CUSTOM1_RS1 0x202b -#define MASK_CUSTOM1_RS1 0x707f -#define MATCH_CUSTOM1_RS1_RS2 0x302b -#define MASK_CUSTOM1_RS1_RS2 0x707f -#define MATCH_CUSTOM1_RD 0x402b -#define MASK_CUSTOM1_RD 0x707f -#define MATCH_CUSTOM1_RD_RS1 0x602b -#define MASK_CUSTOM1_RD_RS1 0x707f -#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b -#define MASK_CUSTOM1_RD_RS1_RS2 0x707f -#define MATCH_CUSTOM2 0x5b -#define MASK_CUSTOM2 0x707f -#define MATCH_CUSTOM2_RS1 0x205b -#define MASK_CUSTOM2_RS1 0x707f -#define MATCH_CUSTOM2_RS1_RS2 0x305b -#define MASK_CUSTOM2_RS1_RS2 0x707f -#define MATCH_CUSTOM2_RD 0x405b -#define MASK_CUSTOM2_RD 0x707f -#define MATCH_CUSTOM2_RD_RS1 0x605b -#define MASK_CUSTOM2_RD_RS1 0x707f -#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b -#define MASK_CUSTOM2_RD_RS1_RS2 0x707f -#define MATCH_CUSTOM3 0x7b -#define MASK_CUSTOM3 0x707f -#define MATCH_CUSTOM3_RS1 0x207b -#define MASK_CUSTOM3_RS1 0x707f -#define MATCH_CUSTOM3_RS1_RS2 0x307b -#define MASK_CUSTOM3_RS1_RS2 0x707f -#define MATCH_CUSTOM3_RD 0x407b -#define MASK_CUSTOM3_RD 0x707f -#define MATCH_CUSTOM3_RD_RS1 0x607b -#define MASK_CUSTOM3_RD_RS1 0x707f -#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b -#define MASK_CUSTOM3_RD_RS1_RS2 0x707f -#define CSR_FFLAGS 0x1 -#define CSR_FRM 0x2 -#define CSR_FCSR 0x3 -#define CSR_CYCLE 0xc00 -#define CSR_TIME 0xc01 -#define CSR_INSTRET 0xc02 -#define CSR_HPMCOUNTER3 0xc03 -#define CSR_HPMCOUNTER4 0xc04 -#define CSR_HPMCOUNTER5 0xc05 -#define CSR_HPMCOUNTER6 0xc06 -#define CSR_HPMCOUNTER7 0xc07 -#define CSR_HPMCOUNTER8 0xc08 -#define CSR_HPMCOUNTER9 0xc09 -#define CSR_HPMCOUNTER10 0xc0a -#define CSR_HPMCOUNTER11 0xc0b -#define CSR_HPMCOUNTER12 0xc0c -#define CSR_HPMCOUNTER13 0xc0d -#define CSR_HPMCOUNTER14 0xc0e -#define CSR_HPMCOUNTER15 0xc0f -#define CSR_HPMCOUNTER16 0xc10 -#define CSR_HPMCOUNTER17 0xc11 -#define CSR_HPMCOUNTER18 0xc12 -#define CSR_HPMCOUNTER19 0xc13 -#define CSR_HPMCOUNTER20 0xc14 -#define CSR_HPMCOUNTER21 0xc15 -#define CSR_HPMCOUNTER22 0xc16 -#define CSR_HPMCOUNTER23 0xc17 -#define CSR_HPMCOUNTER24 0xc18 -#define CSR_HPMCOUNTER25 0xc19 -#define CSR_HPMCOUNTER26 0xc1a -#define CSR_HPMCOUNTER27 0xc1b -#define CSR_HPMCOUNTER28 0xc1c -#define CSR_HPMCOUNTER29 0xc1d -#define CSR_HPMCOUNTER30 0xc1e -#define CSR_HPMCOUNTER31 0xc1f -#define CSR_SSTATUS 0x100 -#define CSR_SIE 0x104 -#define CSR_STVEC 0x105 -#define CSR_SSCRATCH 0x140 -#define CSR_SEPC 0x141 -#define CSR_SCAUSE 0x142 -#define CSR_SBADADDR 0x143 -#define CSR_SIP 0x144 -#define CSR_SPTBR 0x180 -#define CSR_MSTATUS 0x300 -#define CSR_MISA 0x301 -#define CSR_MEDELEG 0x302 -#define CSR_MIDELEG 0x303 -#define CSR_MIE 0x304 -#define CSR_MTVEC 0x305 -#define CSR_MSCRATCH 0x340 -#define CSR_MEPC 0x341 -#define CSR_MCAUSE 0x342 -#define CSR_MBADADDR 0x343 -#define CSR_MIP 0x344 -#define CSR_TSELECT 0x7a0 -#define CSR_TDATA1 0x7a1 -#define CSR_TDATA2 0x7a2 -#define CSR_TDATA3 0x7a3 -#define CSR_DCSR 0x7b0 -#define CSR_DPC 0x7b1 -#define CSR_DSCRATCH 0x7b2 -#define CSR_MCYCLE 0xb00 -#define CSR_MINSTRET 0xb02 -#define CSR_MHPMCOUNTER3 0xb03 -#define CSR_MHPMCOUNTER4 0xb04 -#define CSR_MHPMCOUNTER5 0xb05 -#define CSR_MHPMCOUNTER6 0xb06 -#define CSR_MHPMCOUNTER7 0xb07 -#define CSR_MHPMCOUNTER8 0xb08 -#define CSR_MHPMCOUNTER9 0xb09 -#define CSR_MHPMCOUNTER10 0xb0a -#define CSR_MHPMCOUNTER11 0xb0b -#define CSR_MHPMCOUNTER12 0xb0c -#define CSR_MHPMCOUNTER13 0xb0d -#define CSR_MHPMCOUNTER14 0xb0e -#define CSR_MHPMCOUNTER15 0xb0f -#define CSR_MHPMCOUNTER16 0xb10 -#define CSR_MHPMCOUNTER17 0xb11 -#define CSR_MHPMCOUNTER18 0xb12 -#define CSR_MHPMCOUNTER19 0xb13 -#define CSR_MHPMCOUNTER20 0xb14 -#define CSR_MHPMCOUNTER21 0xb15 -#define CSR_MHPMCOUNTER22 0xb16 -#define CSR_MHPMCOUNTER23 0xb17 -#define CSR_MHPMCOUNTER24 0xb18 -#define CSR_MHPMCOUNTER25 0xb19 -#define CSR_MHPMCOUNTER26 0xb1a -#define CSR_MHPMCOUNTER27 0xb1b -#define CSR_MHPMCOUNTER28 0xb1c -#define CSR_MHPMCOUNTER29 0xb1d -#define CSR_MHPMCOUNTER30 0xb1e -#define CSR_MHPMCOUNTER31 0xb1f -#define CSR_MUCOUNTEREN 0x320 -#define CSR_MSCOUNTEREN 0x321 -#define CSR_MHPMEVENT3 0x323 -#define CSR_MHPMEVENT4 0x324 -#define CSR_MHPMEVENT5 0x325 -#define CSR_MHPMEVENT6 0x326 -#define CSR_MHPMEVENT7 0x327 -#define CSR_MHPMEVENT8 0x328 -#define CSR_MHPMEVENT9 0x329 -#define CSR_MHPMEVENT10 0x32a -#define CSR_MHPMEVENT11 0x32b -#define CSR_MHPMEVENT12 0x32c -#define CSR_MHPMEVENT13 0x32d -#define CSR_MHPMEVENT14 0x32e -#define CSR_MHPMEVENT15 0x32f -#define CSR_MHPMEVENT16 0x330 -#define CSR_MHPMEVENT17 0x331 -#define CSR_MHPMEVENT18 0x332 -#define CSR_MHPMEVENT19 0x333 -#define CSR_MHPMEVENT20 0x334 -#define CSR_MHPMEVENT21 0x335 -#define CSR_MHPMEVENT22 0x336 -#define CSR_MHPMEVENT23 0x337 -#define CSR_MHPMEVENT24 0x338 -#define CSR_MHPMEVENT25 0x339 -#define CSR_MHPMEVENT26 0x33a -#define CSR_MHPMEVENT27 0x33b -#define CSR_MHPMEVENT28 0x33c -#define CSR_MHPMEVENT29 0x33d -#define CSR_MHPMEVENT30 0x33e -#define CSR_MHPMEVENT31 0x33f -#define CSR_MVENDORID 0xf11 -#define CSR_MARCHID 0xf12 -#define CSR_MIMPID 0xf13 -#define CSR_MHARTID 0xf14 -#define CSR_CYCLEH 0xc80 -#define CSR_TIMEH 0xc81 -#define CSR_INSTRETH 0xc82 -#define CSR_HPMCOUNTER3H 0xc83 -#define CSR_HPMCOUNTER4H 0xc84 -#define CSR_HPMCOUNTER5H 0xc85 -#define CSR_HPMCOUNTER6H 0xc86 -#define CSR_HPMCOUNTER7H 0xc87 -#define CSR_HPMCOUNTER8H 0xc88 -#define CSR_HPMCOUNTER9H 0xc89 -#define CSR_HPMCOUNTER10H 0xc8a -#define CSR_HPMCOUNTER11H 0xc8b -#define CSR_HPMCOUNTER12H 0xc8c -#define CSR_HPMCOUNTER13H 0xc8d -#define CSR_HPMCOUNTER14H 0xc8e -#define CSR_HPMCOUNTER15H 0xc8f -#define CSR_HPMCOUNTER16H 0xc90 -#define CSR_HPMCOUNTER17H 0xc91 -#define CSR_HPMCOUNTER18H 0xc92 -#define CSR_HPMCOUNTER19H 0xc93 -#define CSR_HPMCOUNTER20H 0xc94 -#define CSR_HPMCOUNTER21H 0xc95 -#define CSR_HPMCOUNTER22H 0xc96 -#define CSR_HPMCOUNTER23H 0xc97 -#define CSR_HPMCOUNTER24H 0xc98 -#define CSR_HPMCOUNTER25H 0xc99 -#define CSR_HPMCOUNTER26H 0xc9a -#define CSR_HPMCOUNTER27H 0xc9b -#define CSR_HPMCOUNTER28H 0xc9c -#define CSR_HPMCOUNTER29H 0xc9d -#define CSR_HPMCOUNTER30H 0xc9e -#define CSR_HPMCOUNTER31H 0xc9f -#define CSR_MCYCLEH 0xb80 -#define CSR_MINSTRETH 0xb82 -#define CSR_MHPMCOUNTER3H 0xb83 -#define CSR_MHPMCOUNTER4H 0xb84 -#define CSR_MHPMCOUNTER5H 0xb85 -#define CSR_MHPMCOUNTER6H 0xb86 -#define CSR_MHPMCOUNTER7H 0xb87 -#define CSR_MHPMCOUNTER8H 0xb88 -#define CSR_MHPMCOUNTER9H 0xb89 -#define CSR_MHPMCOUNTER10H 0xb8a -#define CSR_MHPMCOUNTER11H 0xb8b -#define CSR_MHPMCOUNTER12H 0xb8c -#define CSR_MHPMCOUNTER13H 0xb8d -#define CSR_MHPMCOUNTER14H 0xb8e -#define CSR_MHPMCOUNTER15H 0xb8f -#define CSR_MHPMCOUNTER16H 0xb90 -#define CSR_MHPMCOUNTER17H 0xb91 -#define CSR_MHPMCOUNTER18H 0xb92 -#define CSR_MHPMCOUNTER19H 0xb93 -#define CSR_MHPMCOUNTER20H 0xb94 -#define CSR_MHPMCOUNTER21H 0xb95 -#define CSR_MHPMCOUNTER22H 0xb96 -#define CSR_MHPMCOUNTER23H 0xb97 -#define CSR_MHPMCOUNTER24H 0xb98 -#define CSR_MHPMCOUNTER25H 0xb99 -#define CSR_MHPMCOUNTER26H 0xb9a -#define CSR_MHPMCOUNTER27H 0xb9b -#define CSR_MHPMCOUNTER28H 0xb9c -#define CSR_MHPMCOUNTER29H 0xb9d -#define CSR_MHPMCOUNTER30H 0xb9e -#define CSR_MHPMCOUNTER31H 0xb9f -#define CAUSE_MISALIGNED_FETCH 0x0 -#define CAUSE_FAULT_FETCH 0x1 -#define CAUSE_ILLEGAL_INSTRUCTION 0x2 -#define CAUSE_BREAKPOINT 0x3 -#define CAUSE_MISALIGNED_LOAD 0x4 -#define CAUSE_FAULT_LOAD 0x5 -#define CAUSE_MISALIGNED_STORE 0x6 -#define CAUSE_FAULT_STORE 0x7 -#define CAUSE_USER_ECALL 0x8 -#define CAUSE_SUPERVISOR_ECALL 0x9 -#define CAUSE_HYPERVISOR_ECALL 0xa -#define CAUSE_MACHINE_ECALL 0xb -#endif -#ifdef DECLARE_INSN -DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) -DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) -DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) -DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) -DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) -DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) -DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) -DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) -DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) -DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) -DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) -DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) -DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) -DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) -DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) -DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) -DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) -DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) -DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) -DECLARE_INSN(add, MATCH_ADD, MASK_ADD) -DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) -DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) -DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) -DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) -DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) -DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) -DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) -DECLARE_INSN(or, MATCH_OR, MASK_OR) -DECLARE_INSN(and, MATCH_AND, MASK_AND) -DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) -DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) -DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) -DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) -DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) -DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) -DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) -DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) -DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) -DECLARE_INSN(lb, MATCH_LB, MASK_LB) -DECLARE_INSN(lh, MATCH_LH, MASK_LH) -DECLARE_INSN(lw, MATCH_LW, MASK_LW) -DECLARE_INSN(ld, MATCH_LD, MASK_LD) -DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) -DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) -DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) -DECLARE_INSN(sb, MATCH_SB, MASK_SB) -DECLARE_INSN(sh, MATCH_SH, MASK_SH) -DECLARE_INSN(sw, MATCH_SW, MASK_SW) -DECLARE_INSN(sd, MATCH_SD, MASK_SD) -DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) -DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) -DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) -DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) -DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) -DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) -DECLARE_INSN(div, MATCH_DIV, MASK_DIV) -DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) -DECLARE_INSN(rem, MATCH_REM, MASK_REM) -DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) -DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) -DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) -DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) -DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) -DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) -DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) -DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) -DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) -DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) -DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) -DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) -DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) -DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) -DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) -DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) -DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) -DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) -DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) -DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) -DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) -DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) -DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) -DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) -DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) -DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) -DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) -DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) -DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) -DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) -DECLARE_INSN(uret, MATCH_URET, MASK_URET) -DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) -DECLARE_INSN(hret, MATCH_HRET, MASK_HRET) -DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) -DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) -DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM) -DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) -DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) -DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) -DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) -DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) -DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) -DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) -DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) -DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) -DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) -DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) -DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) -DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) -DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) -DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) -DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) -DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) -DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) -DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) -DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) -DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) -DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) -DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) -DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) -DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) -DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) -DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) -DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) -DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) -DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) -DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) -DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) -DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) -DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) -DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) -DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) -DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) -DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) -DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) -DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) -DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) -DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) -DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) -DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) -DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) -DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) -DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) -DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) -DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) -DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) -DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) -DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) -DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) -DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) -DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) -DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) -DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) -DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) -DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) -DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) -DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) -DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) -DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) -DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) -DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) -DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) -DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) -DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) -DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) -DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) -DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) -DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) -DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) -DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) -DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) -DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) -DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) -DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) -DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) -DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) -DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) -DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) -DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) -DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) -DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) -DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) -DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) -DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) -DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) -DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) -DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) -DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) -DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) -DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) -DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) -DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) -DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) -DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) -DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) -DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) -DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) -DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) -DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) -DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) -DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) -DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) -DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) -DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) -DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) -DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) -DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) -DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) -DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) -DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) -DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) -DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) -DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) -DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) -DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) -DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) -DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) -DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) -DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) -DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) -DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) -DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) -DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) -DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) -DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) -DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) -DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) -DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) -DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) -DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) -DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) -#endif -#ifdef DECLARE_CSR -DECLARE_CSR(fflags, CSR_FFLAGS) -DECLARE_CSR(frm, CSR_FRM) -DECLARE_CSR(fcsr, CSR_FCSR) -DECLARE_CSR(cycle, CSR_CYCLE) -DECLARE_CSR(time, CSR_TIME) -DECLARE_CSR(instret, CSR_INSTRET) -DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) -DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) -DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) -DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) -DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) -DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) -DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) -DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) -DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) -DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) -DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) -DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) -DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) -DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) -DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) -DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) -DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) -DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) -DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) -DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) -DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) -DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) -DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) -DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) -DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) -DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) -DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) -DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) -DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) -DECLARE_CSR(sstatus, CSR_SSTATUS) -DECLARE_CSR(sie, CSR_SIE) -DECLARE_CSR(stvec, CSR_STVEC) -DECLARE_CSR(sscratch, CSR_SSCRATCH) -DECLARE_CSR(sepc, CSR_SEPC) -DECLARE_CSR(scause, CSR_SCAUSE) -DECLARE_CSR(sbadaddr, CSR_SBADADDR) -DECLARE_CSR(sip, CSR_SIP) -DECLARE_CSR(sptbr, CSR_SPTBR) -DECLARE_CSR(mstatus, CSR_MSTATUS) -DECLARE_CSR(misa, CSR_MISA) -DECLARE_CSR(medeleg, CSR_MEDELEG) -DECLARE_CSR(mideleg, CSR_MIDELEG) -DECLARE_CSR(mie, CSR_MIE) -DECLARE_CSR(mtvec, CSR_MTVEC) -DECLARE_CSR(mscratch, CSR_MSCRATCH) -DECLARE_CSR(mepc, CSR_MEPC) -DECLARE_CSR(mcause, CSR_MCAUSE) -DECLARE_CSR(mbadaddr, CSR_MBADADDR) -DECLARE_CSR(mip, CSR_MIP) -DECLARE_CSR(tselect, CSR_TSELECT) -DECLARE_CSR(tdata1, CSR_TDATA1) -DECLARE_CSR(tdata2, CSR_TDATA2) -DECLARE_CSR(tdata3, CSR_TDATA3) -DECLARE_CSR(dcsr, CSR_DCSR) -DECLARE_CSR(dpc, CSR_DPC) -DECLARE_CSR(dscratch, CSR_DSCRATCH) -DECLARE_CSR(mcycle, CSR_MCYCLE) -DECLARE_CSR(minstret, CSR_MINSTRET) -DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) -DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) -DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) -DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) -DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) -DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) -DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) -DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) -DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) -DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) -DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) -DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) -DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) -DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) -DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) -DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) -DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) -DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) -DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) -DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) -DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) -DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) -DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) -DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) -DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) -DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) -DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) -DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) -DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) -DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) -DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) -DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) -DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) -DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) -DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) -DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) -DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) -DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) -DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) -DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) -DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) -DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) -DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) -DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) -DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) -DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) -DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) -DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) -DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) -DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) -DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) -DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) -DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) -DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) -DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) -DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) -DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) -DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) -DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) -DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) -DECLARE_CSR(mvendorid, CSR_MVENDORID) -DECLARE_CSR(marchid, CSR_MARCHID) -DECLARE_CSR(mimpid, CSR_MIMPID) -DECLARE_CSR(mhartid, CSR_MHARTID) -DECLARE_CSR(cycleh, CSR_CYCLEH) -DECLARE_CSR(timeh, CSR_TIMEH) -DECLARE_CSR(instreth, CSR_INSTRETH) -DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) -DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) -DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) -DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) -DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) -DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) -DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) -DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) -DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) -DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) -DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) -DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) -DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) -DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) -DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) -DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) -DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) -DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) -DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) -DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) -DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) -DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) -DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) -DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) -DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) -DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) -DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) -DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) -DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) -DECLARE_CSR(mcycleh, CSR_MCYCLEH) -DECLARE_CSR(minstreth, CSR_MINSTRETH) -DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) -DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) -DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) -DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) -DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) -DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) -DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) -DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) -DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) -DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) -DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) -DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) -DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) -DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) -DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) -DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) -DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) -DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) -DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) -DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) -DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) -DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) -DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) -DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) -DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) -DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) -DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) -DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) -DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) -#endif -#ifdef DECLARE_CAUSE -DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) -DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH) -DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) -DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) -DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) -DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD) -DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) -DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE) -DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) -DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) -DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) -DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) -#endif diff --git a/tests/htif.ld b/tests/htif.ld new file mode 120000 index 00000000..b527740e --- /dev/null +++ b/tests/htif.ld @@ -0,0 +1 @@ +../toolchains/libgloss/util/htif.ld \ No newline at end of file diff --git a/tests/libgloss.mk b/tests/libgloss.mk new file mode 100644 index 00000000..2272df33 --- /dev/null +++ b/tests/libgloss.mk @@ -0,0 +1,50 @@ +# Handle libgloss-htif dependency +ifndef libgloss + +ifndef GCC +$(error GCC is not defined) +endif + +libgloss_specs := htif_nano.specs + +# Test whether libgloss-htif is globally installed and usable +# Define BUILD_LIBGLOSS=1 to unconditionally force a local build +BUILD_LIBGLOSS ?= $(shell { echo 'int main(void) { return 0; }' | \ + $(GCC) -xc -specs=$(libgloss_specs) -o /dev/null - 2> /dev/null ; } || \ + echo "$$?") + +ifneq ($(BUILD_LIBGLOSS),) +$(info libgloss-htif: Using local build) + +libgloss_srcdir := ../toolchains/libgloss +libgloss_builddir := libgloss +libgloss_specs := $(libgloss_srcdir)/util/$(libgloss_specs) +libgloss_lib := $(libgloss_builddir)/libgloss_htif.a +libgloss := $(libgloss_lib) $(libgloss_specs) htif.ld + +LDFLAGS += -L libgloss + +$(libgloss_builddir)/Makefile: $(libgloss_srcdir)/configure + mkdir -p $(dir $@) + cd $(dir $@) && $(realpath $<) \ + --prefix=$(shell $(GCC) -print-sysroot) \ + --host=$(TARGET) \ + --disable-multilib + +$(libgloss_lib): $(libgloss_builddir)/Makefile + $(MAKE) -C $(dir $^) + +.PHONY: libgloss +libgloss: $(libgloss) + +else + +$(info libgloss-htif: Using global install) +libgloss := # No additional prerequisites + +endif + +CFLAGS += -specs=$(libgloss_specs) +LDFLAGS += -specs=$(libgloss_specs) + +endif # libgloss diff --git a/tests/link.ld b/tests/link.ld deleted file mode 100644 index b39944d6..00000000 --- a/tests/link.ld +++ /dev/null @@ -1,65 +0,0 @@ -/*======================================================================*/ -/* Proxy kernel linker script */ -/*======================================================================*/ -/* This is the linker script used when building the proxy kernel. */ - -/*----------------------------------------------------------------------*/ -/* Setup */ -/*----------------------------------------------------------------------*/ - -/* The OUTPUT_ARCH command specifies the machine architecture where the - argument is one of the names used in the BFD library. More - specifically one of the entires in bfd/cpu-mips.c */ - -OUTPUT_ARCH( "riscv" ) -ENTRY(_start) - -/*----------------------------------------------------------------------*/ -/* Sections */ -/*----------------------------------------------------------------------*/ - -SECTIONS -{ - - /* text: test code section */ - . = 0x80000000; - .text.init : { *(.text.init) } - - .tohost ALIGN(0x1000) : { *(.tohost) } - - .text : { *(.text) } - - /* data segment */ - .data ALIGN(0x40) : { *(.data) } - - .sdata : { - __global_pointer$ = . + 0x800; - *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*) - *(.sdata .sdata.* .gnu.linkonce.s.*) - } - - /* bss segment */ - .sbss : { - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - } - .bss ALIGN(0x40) : { *(.bss) } - - /* thread-local data segment */ - .tdata : - { - _tls_data = .; - *(.tdata.begin) - *(.tdata) - *(.tdata.end) - } - .tbss : - { - *(.tbss) - *(.tbss.end) - } - - /* End of uninitalized data segement */ - _end = .; -} - diff --git a/tests/nic-loopback.c b/tests/nic-loopback.c index 1d3c7b96..74eced7d 100644 --- a/tests/nic-loopback.c +++ b/tests/nic-loopback.c @@ -3,8 +3,8 @@ #include #include +#include #include "nic.h" -#include "encoding.h" #define NPACKETS 10 #define TEST_OFFSET 3 diff --git a/tests/syscalls.c b/tests/syscalls.c deleted file mode 100644 index 0a7d6b72..00000000 --- a/tests/syscalls.c +++ /dev/null @@ -1,470 +0,0 @@ -// See LICENSE for license details. - -#include -#include -#include -#include -#include -#include -#include "util.h" - -#define SYS_write 64 - -#undef strcmp - -extern volatile uint64_t tohost; -extern volatile uint64_t fromhost; - -static uintptr_t syscall(uintptr_t which, uint64_t arg0, uint64_t arg1, uint64_t arg2) -{ - volatile uint64_t magic_mem[8] __attribute__((aligned(64))); - magic_mem[0] = which; - magic_mem[1] = arg0; - magic_mem[2] = arg1; - magic_mem[3] = arg2; - __sync_synchronize(); - - tohost = (uintptr_t)magic_mem; - while (fromhost == 0) - ; - fromhost = 0; - - __sync_synchronize(); - return magic_mem[0]; -} - -#define NUM_COUNTERS 2 -static uintptr_t counters[NUM_COUNTERS]; -static char* counter_names[NUM_COUNTERS]; - -void setStats(int enable) -{ - int i = 0; -#define READ_CTR(name) do { \ - while (i >= NUM_COUNTERS) ; \ - uintptr_t csr = read_csr(name); \ - if (!enable) { csr -= counters[i]; counter_names[i] = #name; } \ - counters[i++] = csr; \ - } while (0) - - READ_CTR(mcycle); - READ_CTR(minstret); - -#undef READ_CTR -} - -void __attribute__((noreturn)) tohost_exit(uintptr_t code) -{ - tohost = (code << 1) | 1; - while (1); -} - -uintptr_t __attribute__((weak)) handle_trap(uintptr_t cause, uintptr_t epc, uintptr_t regs[32]) -{ - tohost_exit(1337); -} - -void exit(int code) -{ - tohost_exit(code); -} - -void abort() -{ - exit(128 + SIGABRT); -} - -void printstr(const char* s) -{ - syscall(SYS_write, 1, (uintptr_t)s, strlen(s)); -} - -void __attribute__((weak)) thread_entry(int cid, int nc) -{ - // multi-threaded programs override this function. - // for the case of single-threaded programs, only let core 0 proceed. - while (cid != 0); -} - -int __attribute__((weak)) main(int argc, char** argv) -{ - // single-threaded programs override this function. - printstr("Implement main(), foo!\n"); - return -1; -} - -static void init_tls() -{ - register void* thread_pointer asm("tp"); - extern char _tls_data; - extern __thread char _tdata_begin, _tdata_end, _tbss_end; - size_t tdata_size = &_tdata_end - &_tdata_begin; - memcpy(thread_pointer, &_tls_data, tdata_size); - size_t tbss_size = &_tbss_end - &_tdata_end; - memset(thread_pointer + tdata_size, 0, tbss_size); -} - -void _init(int cid, int nc) -{ - init_tls(); - thread_entry(cid, nc); - - // only single-threaded programs should ever get here. - int ret = main(0, 0); - - char buf[NUM_COUNTERS * 32] __attribute__((aligned(64))); - char* pbuf = buf; - for (int i = 0; i < NUM_COUNTERS; i++) - if (counters[i]) - pbuf += sprintf(pbuf, "%s = %d\n", counter_names[i], counters[i]); - if (pbuf != buf) - printstr(buf); - - exit(ret); -} - -#undef putchar -int putchar(int ch) -{ - static __thread char buf[64] __attribute__((aligned(64))); - static __thread int buflen = 0; - - buf[buflen++] = ch; - - if (ch == '\n' || buflen == sizeof(buf)) - { - syscall(SYS_write, 1, (uintptr_t)buf, buflen); - buflen = 0; - } - - return 0; -} - -void printhex(uint64_t x) -{ - char str[17]; - int i; - for (i = 0; i < 16; i++) - { - str[15-i] = (x & 0xF) + ((x & 0xF) < 10 ? '0' : 'a'-10); - x >>= 4; - } - str[16] = 0; - - printstr(str); -} - -static inline void printnum(void (*putch)(int, void**), void **putdat, - unsigned long long num, unsigned base, int width, int padc) -{ - unsigned digs[sizeof(num)*CHAR_BIT]; - int pos = 0; - - while (1) - { - digs[pos++] = num % base; - if (num < base) - break; - num /= base; - } - - while (width-- > pos) - putch(padc, putdat); - - while (pos-- > 0) - putch(digs[pos] + (digs[pos] >= 10 ? 'a' - 10 : '0'), putdat); -} - -static unsigned long long getuint(va_list *ap, int lflag) -{ - if (lflag >= 2) - return va_arg(*ap, unsigned long long); - else if (lflag) - return va_arg(*ap, unsigned long); - else - return va_arg(*ap, unsigned int); -} - -static long long getint(va_list *ap, int lflag) -{ - if (lflag >= 2) - return va_arg(*ap, long long); - else if (lflag) - return va_arg(*ap, long); - else - return va_arg(*ap, int); -} - -static void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap) -{ - register const char* p; - const char* last_fmt; - register int ch, err; - unsigned long long num; - int base, lflag, width, precision, altflag; - char padc; - - while (1) { - while ((ch = *(unsigned char *) fmt) != '%') { - if (ch == '\0') - return; - fmt++; - putch(ch, putdat); - } - fmt++; - - // Process a %-escape sequence - last_fmt = fmt; - padc = ' '; - width = -1; - precision = -1; - lflag = 0; - altflag = 0; - reswitch: - switch (ch = *(unsigned char *) fmt++) { - - // flag to pad on the right - case '-': - padc = '-'; - goto reswitch; - - // flag to pad with 0's instead of spaces - case '0': - padc = '0'; - goto reswitch; - - // width field - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - for (precision = 0; ; ++fmt) { - precision = precision * 10 + ch - '0'; - ch = *fmt; - if (ch < '0' || ch > '9') - break; - } - goto process_precision; - - case '*': - precision = va_arg(ap, int); - goto process_precision; - - case '.': - if (width < 0) - width = 0; - goto reswitch; - - case '#': - altflag = 1; - goto reswitch; - - process_precision: - if (width < 0) - width = precision, precision = -1; - goto reswitch; - - // long flag (doubled for long long) - case 'l': - lflag++; - goto reswitch; - - // character - case 'c': - putch(va_arg(ap, int), putdat); - break; - - // string - case 's': - if ((p = va_arg(ap, char *)) == NULL) - p = "(null)"; - if (width > 0 && padc != '-') - for (width -= strnlen(p, precision); width > 0; width--) - putch(padc, putdat); - for (; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width--) { - putch(ch, putdat); - p++; - } - for (; width > 0; width--) - putch(' ', putdat); - break; - - // (signed) decimal - case 'd': - num = getint(&ap, lflag); - if ((long long) num < 0) { - putch('-', putdat); - num = -(long long) num; - } - base = 10; - goto signed_number; - - // unsigned decimal - case 'u': - base = 10; - goto unsigned_number; - - // (unsigned) octal - case 'o': - // should do something with padding so it's always 3 octits - base = 8; - goto unsigned_number; - - // pointer - case 'p': - static_assert(sizeof(long) == sizeof(void*)); - lflag = 1; - putch('0', putdat); - putch('x', putdat); - /* fall through to 'x' */ - - // (unsigned) hexadecimal - case 'x': - base = 16; - unsigned_number: - num = getuint(&ap, lflag); - signed_number: - printnum(putch, putdat, num, base, width, padc); - break; - - // escaped '%' character - case '%': - putch(ch, putdat); - break; - - // unrecognized escape sequence - just print it literally - default: - putch('%', putdat); - fmt = last_fmt; - break; - } - } -} - -int printf(const char* fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - - vprintfmt((void*)putchar, 0, fmt, ap); - - va_end(ap); - return 0; // incorrect return value, but who cares, anyway? -} - -int sprintf(char* str, const char* fmt, ...) -{ - va_list ap; - char* str0 = str; - va_start(ap, fmt); - - void sprintf_putch(int ch, void** data) - { - char** pstr = (char**)data; - **pstr = ch; - (*pstr)++; - } - - vprintfmt(sprintf_putch, (void**)&str, fmt, ap); - *str = 0; - - va_end(ap); - return str - str0; -} - -void* memcpy(void* dest, const void* src, size_t len) -{ - if ((((uintptr_t)dest | (uintptr_t)src | len) & (sizeof(uintptr_t)-1)) == 0) { - const uintptr_t* s = src; - uintptr_t *d = dest; - while (d < (uintptr_t*)(dest + len)) - *d++ = *s++; - } else { - const char* s = src; - char *d = dest; - while (d < (char*)(dest + len)) - *d++ = *s++; - } - return dest; -} - -void* memset(void* dest, int byte, size_t len) -{ - if ((((uintptr_t)dest | len) & (sizeof(uintptr_t)-1)) == 0) { - uintptr_t word = byte & 0xFF; - word |= word << 8; - word |= word << 16; - word |= word << 16 << 16; - - uintptr_t *d = dest; - while (d < (uintptr_t*)(dest + len)) - *d++ = word; - } else { - char *d = dest; - while (d < (char*)(dest + len)) - *d++ = byte; - } - return dest; -} - -size_t strlen(const char *s) -{ - const char *p = s; - while (*p) - p++; - return p - s; -} - -size_t strnlen(const char *s, size_t n) -{ - const char *p = s; - while (n-- && *p) - p++; - return p - s; -} - -int strcmp(const char* s1, const char* s2) -{ - unsigned char c1, c2; - - do { - c1 = *s1++; - c2 = *s2++; - } while (c1 != 0 && c1 == c2); - - return c1 - c2; -} - -char* strcpy(char* dest, const char* src) -{ - char* d = dest; - while ((*d++ = *src++)) - ; - return dest; -} - -long atol(const char* str) -{ - long res = 0; - int sign = 0; - - while (*str == ' ') - str++; - - if (*str == '-' || *str == '+') { - sign = *str == '-'; - str++; - } - - while (*str) { - res *= 10; - res += *str++ - '0'; - } - - return sign ? -res : res; -} diff --git a/tests/util.h b/tests/util.h deleted file mode 100644 index 22f81cf9..00000000 --- a/tests/util.h +++ /dev/null @@ -1,135 +0,0 @@ -// See LICENSE for license details. - -#ifndef __UTIL_H -#define __UTIL_H - -//-------------------------------------------------------------------------- -// Macros - -// Set HOST_DEBUG to 1 if you are going to compile this for a host -// machine (ie Athena/Linux) for debug purposes and set HOST_DEBUG -// to 0 if you are compiling with the smips-gcc toolchain. - -#ifndef HOST_DEBUG -#define HOST_DEBUG 0 -#endif - -// Set PREALLOCATE to 1 if you want to preallocate the benchmark -// function before starting stats. If you have instruction/data -// caches and you don't want to count the overhead of misses, then -// you will need to use preallocation. - -#ifndef PREALLOCATE -#define PREALLOCATE 0 -#endif - -// Set SET_STATS to 1 if you want to carve out the piece that actually -// does the computation. - -#if HOST_DEBUG -#include -static void setStats(int enable) {} -#else -extern void setStats(int enable); -#endif - -#include - -#define static_assert(cond) switch(0) { case 0: case !!(long)(cond): ; } - -static void printArray(const char name[], int n, const int arr[]) -{ -#if HOST_DEBUG - int i; - printf( " %10s :", name ); - for ( i = 0; i < n; i++ ) - printf( " %3d ", arr[i] ); - printf( "\n" ); -#endif -} - -static void printDoubleArray(const char name[], int n, const double arr[]) -{ -#if HOST_DEBUG - int i; - printf( " %10s :", name ); - for ( i = 0; i < n; i++ ) - printf( " %g ", arr[i] ); - printf( "\n" ); -#endif -} - -static int verify(int n, const volatile int* test, const int* verify) -{ - int i; - // Unrolled for faster verification - for (i = 0; i < n/2*2; i+=2) - { - int t0 = test[i], t1 = test[i+1]; - int v0 = verify[i], v1 = verify[i+1]; - if (t0 != v0) return i+1; - if (t1 != v1) return i+2; - } - if (n % 2 != 0 && test[n-1] != verify[n-1]) - return n; - return 0; -} - -static int verifyDouble(int n, const volatile double* test, const double* verify) -{ - int i; - // Unrolled for faster verification - for (i = 0; i < n/2*2; i+=2) - { - double t0 = test[i], t1 = test[i+1]; - double v0 = verify[i], v1 = verify[i+1]; - int eq1 = t0 == v0, eq2 = t1 == v1; - if (!(eq1 & eq2)) return i+1+eq1; - } - if (n % 2 != 0 && test[n-1] != verify[n-1]) - return n; - return 0; -} - -static void __attribute__((noinline)) barrier(int ncores) -{ - static volatile int sense; - static volatile int count; - static __thread int threadsense; - - __sync_synchronize(); - - threadsense = !threadsense; - if (__sync_fetch_and_add(&count, 1) == ncores-1) - { - count = 0; - sense = threadsense; - } - else while(sense != threadsense) - ; - - __sync_synchronize(); -} - -static uint64_t lfsr(uint64_t x) -{ - uint64_t bit = (x ^ (x >> 1)) & 1; - return (x >> 1) | (bit << 62); -} - -#ifdef __riscv -#include "encoding.h" -#endif - -#define stringify_1(s) #s -#define stringify(s) stringify_1(s) -#define stats(code, iter) do { \ - unsigned long _c = -read_csr(mcycle), _i = -read_csr(minstret); \ - code; \ - _c += read_csr(mcycle), _i += read_csr(minstret); \ - if (cid == 0) \ - printf("\n%s: %ld cycles, %ld.%ld cycles/iter, %ld.%ld CPI\n", \ - stringify(code), _c, _c/iter, 10*_c/iter%10, _c/_i, 10*_c/_i%10); \ - } while(0) - -#endif //__UTIL_H From d277984eab129f259fd5af3d62a43586477c2e12 Mon Sep 17 00:00:00 2001 From: Baltazar Ortiz Date: Fri, 10 Jan 2020 11:02:21 -0800 Subject: [PATCH 37/75] Update scratchpad config (#371) * Update scratchpad config Previous version didn't compile as per https://github.com/ucb-bar/chipyard/issues/365 * Update docs/Customization/Memory-Hierarchy.rst Co-Authored-By: Abraham Gonzalez * Fix indentation * Update memory hierarchy doc for PR Co-authored-by: Abraham Gonzalez --- docs/Customization/Memory-Hierarchy.rst | 32 ++++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/Customization/Memory-Hierarchy.rst b/docs/Customization/Memory-Hierarchy.rst index 207e0775..65724483 100644 --- a/docs/Customization/Memory-Hierarchy.rst +++ b/docs/Customization/Memory-Hierarchy.rst @@ -9,19 +9,23 @@ The L1 Caches Each CPU tile has an L1 instruction cache and L1 data cache. The size and associativity of these caches can be configured. The default ``RocketConfig`` uses 16 KiB, 4-way set-associative instruction and data caches. However, -if you use the ``NMediumCores`` or ``NSmallCores`` configurations, you can +if you use the ``NMedCores`` or ``NSmallCores`` configurations, you can configure 4 KiB direct-mapped caches for L1I and L1D. .. code-block:: scala - import freechips.rocketchip.subsystem.{WithNMediumCores, WithNSmallCores} + class SmallRocketConfig extends Config( + new WithTop ++ // use default top + new WithBootROM ++ // use default bootrom + new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ + new freechips.rocketchip.system.BaseConfig) class SmallRocketConfig extends Config( - new WithNSmallCores(1) ++ + new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ new RocketConfig) class MediumRocketConfig extends Config( - new WithNMediumCores(1) ++ + new freechips.rocketchip.subsystem.WithNMedCores(1) ++ new RocketConfig) If you only want to change the size or associativity, there are configuration @@ -41,15 +45,25 @@ mixins for those too. You can also configure the L1 data cache as an data scratchpad instead. However, there are some limitations on this. If you are using a data scratchpad, you can only use a single core and you cannot give the design an external DRAM. +Note that these configurations fully remove the L2 cache and mbus. .. code-block:: scala - import freechips.rocketchip.subsystem.{WithNoMemPort, WithScratchpadsOnly} - + class SmallRocketConfigNoL2 extends Config( + new WithTop ++ // use default top + new WithBootROM ++ // use default bootrom + new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ + new freechips.rocketchip.system.BaseConfig) + class ScratchpadRocketConfig extends Config( - new WithNoMemPort ++ - new WithScratchpadsOnly ++ - new SmallRocketConfig) + new freechips.rocketchip.subsystem.WithNoMemPort ++ + new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ + new freechips.rocketchip.subsystem.WithNBanks(0) ++ + new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ + new SmallRocketConfigNoL2) + +This configuration fully removes the L2 cache and memory bus by setting the +number of channels and number of banks to 0. The SiFive L2 Cache ------------------- From 9df81ccb167502c49a0c760fd8cac0e2061ac54e Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 16 Jan 2020 11:33:04 -0800 Subject: [PATCH 38/75] [sha3] point to README for SW (#378) * [sha3] point to README for SW [skip ci] * [sha3] bump sha3 repo for doc. changes [ci skip] --- docs/Generators/SHA3.rst | 3 +++ generators/sha3 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/Generators/SHA3.rst b/docs/Generators/SHA3.rst index 96b5744a..a61e7e82 100644 --- a/docs/Generators/SHA3.rst +++ b/docs/Generators/SHA3.rst @@ -77,4 +77,7 @@ this mixin is shown here: :start-after: DOC include start: Sha3Rocket :end-before: DOC include end: Sha3Rocket +The SHA3 example baremetal and Linux tests are located in the SHA3 repository. +Please refer to its `README.md`__ for more information on how to run/build the tests. + diff --git a/generators/sha3 b/generators/sha3 index def77259..6814c999 160000 --- a/generators/sha3 +++ b/generators/sha3 @@ -1 +1 @@ -Subproject commit def77259c0c78c05cd3d6104943f3e6d98da5bd2 +Subproject commit 6814c9991336c5092e7ce7c06f7a8e8bc4283958 From 9e2726a2517aaa11c3809f4324642a59eb05d76c Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 16 Jan 2020 11:33:46 -0800 Subject: [PATCH 39/75] Add UART and UARTAdapter to all configs (#348) * [uart] add uart adapter | add uart + adapter to all configs * [uart] bump testchipip | add small documentation in generators section --- build.sbt | 2 +- docs/Generators/TestChipIP.rst | 16 ++++++++++++++-- .../example/src/main/scala/BoomConfigs.scala | 8 ++++++++ .../example/src/main/scala/ConfigMixins.scala | 11 ++++++++++- .../example/src/main/scala/HeteroConfigs.scala | 9 +++++++++ .../example/src/main/scala/RocketConfigs.scala | 18 ++++++++++++++++++ .../example/src/main/scala/TestHarness.scala | 1 + generators/example/src/main/scala/Top.scala | 5 ++++- generators/testchipip | 2 +- 9 files changed, 66 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index 6e30befd..d02c66bb 100644 --- a/build.sbt +++ b/build.sbt @@ -119,7 +119,7 @@ lazy val rocketchip = freshProject("rocketchip", rocketChipDir) .dependsOn(chisel, hardfloat, rocketMacros, rocketConfig) lazy val testchipip = (project in file("generators/testchipip")) - .dependsOn(rocketchip) + .dependsOn(rocketchip, sifive_blocks) .settings(commonSettings) lazy val example = conditionalDependsOn(project in file("generators/example")) diff --git a/docs/Generators/TestChipIP.rst b/docs/Generators/TestChipIP.rst index 7d490c5f..13b516e3 100644 --- a/docs/Generators/TestChipIP.rst +++ b/docs/Generators/TestChipIP.rst @@ -3,13 +3,13 @@ Test Chip IP Chipyard includes a Test Chip IP library which provides various hardware widgets that may be useful when designing SoCs. This includes a :ref:`Serial Adapter`, -:ref:`Block Device Controller`, :ref:`TileLink SERDES`, and :ref:`TileLink Switcher`. +:ref:`Block Device Controller`, :ref:`TileLink SERDES`, :ref:`TileLink Switcher`, and :ref:`UART Adapter`. Serial Adapter -------------- The serial adapter is used by tethered test chips to communicate with the host -processor. An instance of RISC-V frontend server running on the host CPU +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 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 @@ -61,3 +61,15 @@ the select signal once TileLink messages have begun sending. For an example of how to use the switcher, take a look at the ``SwitcherTest`` unit test in the `Test Chip IP unit tests `_. + +UART Adapter +------------ + +The UART Adapter is a device that lives in the TestHarness and connects to the +UART port of the DUT to simulate communication over UART (ex. printing out to UART +during Linux boot). In addition to working with ``stdin/stdout`` of the host, it is able to +output a UART log to a particular file using ``+uartlog=`` during simulation. + +By default, this UART Adapter is added to all systems within Chipyard by adding the +``CanHavePeripheryUARTWithAdapter`` and ``CanHavePeripheryUARTWithAdapterImp`` traits to the ``Top`` system. +These traits add a SiFive UART to the system as well as add the UART Adapter to the TestHarness. diff --git a/generators/example/src/main/scala/BoomConfigs.scala b/generators/example/src/main/scala/BoomConfigs.scala index 3c144d00..0f1535ea 100644 --- a/generators/example/src/main/scala/BoomConfigs.scala +++ b/generators/example/src/main/scala/BoomConfigs.scala @@ -11,6 +11,7 @@ import freechips.rocketchip.config.{Config} class SmallBoomConfig extends Config( new WithTop ++ // use normal top new WithBootROM ++ // use testchipip bootrom + new WithUART ++ // add a UART new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use SiFive L2 cache new boom.common.WithSmallBooms ++ // 1-wide BOOM new boom.common.WithNBoomCores(1) ++ // single-core @@ -19,6 +20,7 @@ class SmallBoomConfig extends Config( class MediumBoomConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithMediumBooms ++ // 2-wide BOOM new boom.common.WithNBoomCores(1) ++ @@ -27,6 +29,7 @@ class MediumBoomConfig extends Config( class LargeBoomConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithLargeBooms ++ // 3-wide BOOM new boom.common.WithNBoomCores(1) ++ @@ -35,6 +38,7 @@ class LargeBoomConfig extends Config( class MegaBoomConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithMegaBooms ++ // 4-wide BOOM new boom.common.WithNBoomCores(1) ++ @@ -43,6 +47,7 @@ class MegaBoomConfig extends Config( class DualSmallBoomConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithSmallBooms ++ new boom.common.WithNBoomCores(2) ++ // dual-core @@ -51,6 +56,7 @@ class DualSmallBoomConfig extends Config( class SmallRV32BoomConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithoutBoomFPU ++ // no fp new boom.common.WithBoomRV32 ++ // rv32 (32bit) @@ -61,6 +67,7 @@ class SmallRV32BoomConfig extends Config( class HwachaLargeBoomConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator new boom.common.WithLargeBooms ++ // 3-wide BOOM @@ -71,6 +78,7 @@ class LoopbackNICBoomConfig extends Config( new WithIceNIC ++ new WithLoopbackNICTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithLargeBooms ++ // 3-wide BOOM new boom.common.WithNBoomCores(1) ++ diff --git a/generators/example/src/main/scala/ConfigMixins.scala b/generators/example/src/main/scala/ConfigMixins.scala index f06cd5f4..441a9289 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -17,6 +17,7 @@ import testchipip._ import hwacha.{Hwacha} import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.uart._ import icenet.{NICKey, NICConfig} @@ -45,11 +46,19 @@ class WithBootROM extends Config((site, here, up) => { * Class to add in GPIO */ class WithGPIO extends Config((site, here, up) => { - case PeripheryGPIOKey => List( + case PeripheryGPIOKey => Seq( GPIOParams(address = 0x10012000, width = 4, includeIOF = false)) }) // DOC include end: WithGPIO +/** + * Class to add in UART + */ +class WithUART extends Config((site, here, up) => { + case PeripheryUARTKey => Seq( + UARTParams(address = 0x54000000L, nTxEntries = 256, nRxEntries = 256)) +}) + // ----------------------------------------------- // BOOM and/or Rocket Top Level System Parameter Mixins // ----------------------------------------------- diff --git a/generators/example/src/main/scala/HeteroConfigs.scala b/generators/example/src/main/scala/HeteroConfigs.scala index 84da15b3..e5cebef9 100644 --- a/generators/example/src/main/scala/HeteroConfigs.scala +++ b/generators/example/src/main/scala/HeteroConfigs.scala @@ -11,6 +11,7 @@ import freechips.rocketchip.config.{Config} class LargeBoomAndRocketConfig extends Config( new WithTop ++ // default top new WithBootROM ++ // default bootrom + new WithUART ++ // add a UART new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use SiFive l2 new boom.common.WithRenumberHarts ++ // avoid hartid overlap new boom.common.WithLargeBooms ++ // 3-wide boom @@ -21,6 +22,7 @@ class LargeBoomAndRocketConfig extends Config( class SmallBoomAndRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ new boom.common.WithSmallBooms ++ // 1-wide boom @@ -32,6 +34,7 @@ class SmallBoomAndRocketConfig extends Config( class HwachaLargeBoomAndHwachaRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new hwacha.DefaultHwachaConfig ++ // add hwacha to all harts new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ @@ -44,6 +47,7 @@ class HwachaLargeBoomAndHwachaRocketConfig extends Config( class RoccLargeBoomAndRoccRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithRoccExample ++ // add example rocc accelerator to all harts new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ @@ -55,6 +59,7 @@ class RoccLargeBoomAndRoccRocketConfig extends Config( class DualLargeBoomAndRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ @@ -66,6 +71,7 @@ class DualLargeBoomAndRocketConfig extends Config( class DualLargeBoomAndHwachaRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new WithMultiRoCC ++ // support heterogeneous rocc new WithMultiRoCCHwacha(2) ++ // put hwacha on hart-2 (rocket) @@ -79,6 +85,7 @@ class DualLargeBoomAndHwachaRocketConfig extends Config( class LargeBoomAndRV32RocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ @@ -91,6 +98,7 @@ class LargeBoomAndRV32RocketConfig extends Config( class DualLargeBoomAndDualRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ @@ -102,6 +110,7 @@ class DualLargeBoomAndDualRocketConfig extends Config( class MultiCoreWithControlCoreConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new WithControlCore ++ // add small control core (last hartid) new boom.common.WithRenumberHarts ++ diff --git a/generators/example/src/main/scala/RocketConfigs.scala b/generators/example/src/main/scala/RocketConfigs.scala index d095980f..edd18a36 100644 --- a/generators/example/src/main/scala/RocketConfigs.scala +++ b/generators/example/src/main/scala/RocketConfigs.scala @@ -11,6 +11,7 @@ import freechips.rocketchip.config.{Config} class RocketConfig extends Config( new WithTop ++ // use default top new WithBootROM ++ // use default bootrom + new WithUART ++ // add a UART new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system @@ -18,6 +19,7 @@ class RocketConfig extends Config( class HwachaRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -27,6 +29,7 @@ class HwachaRocketConfig extends Config( class GemminiRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new gemmini.DefaultGemminiConfig ++ // use Gemmini systolic array GEMM accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -36,6 +39,7 @@ class GemminiRocketConfig extends Config( class RoccRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithRoccExample ++ // use example RoCC-based accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -46,6 +50,7 @@ class jtagRocketConfig extends Config( new WithDTMTop ++ // use top with dtm new freechips.rocketchip.subsystem.WithJtagDTM ++ // add jtag+DTM module to coreplex new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -55,6 +60,7 @@ class jtagRocketConfig extends Config( class dmiRocketConfig extends Config( new WithDTMTop ++ // use top with dtm new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -64,6 +70,7 @@ class dmiRocketConfig extends Config( class PWMRocketConfig extends Config( new WithPWMTop ++ // use top with tilelink-controlled PWM new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -72,6 +79,7 @@ class PWMRocketConfig extends Config( class PWMAXI4RocketConfig extends Config( new WithPWMAXI4Top ++ // use top with axi4-controlled PWM new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -79,6 +87,7 @@ class PWMAXI4RocketConfig extends Config( class GCDRocketConfig extends Config( // add MMIO GCD module new WithGCDTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -87,6 +96,7 @@ class SimBlockDeviceRocketConfig extends Config( new testchipip.WithBlockDevice ++ // add block-device module to peripherybus new WithSimBlockDeviceTop ++ // use top with block-device IOs and connect to simblockdevice new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -95,6 +105,7 @@ class BlockDeviceModelRocketConfig extends Config( new testchipip.WithBlockDevice ++ // add block-device module to periphery bus new WithBlockDeviceModelTop ++ // use top with block-device IOs and connect to a blockdevicemodel new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -104,6 +115,7 @@ class GPIORocketConfig extends Config( new WithGPIO ++ // add GPIOs to the peripherybus new WithGPIOTop ++ // use top with GPIOs new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -112,6 +124,7 @@ class GPIORocketConfig extends Config( class DualCoreRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(2) ++ // dual-core (2 RocketTiles) new freechips.rocketchip.system.BaseConfig) @@ -119,6 +132,7 @@ class DualCoreRocketConfig extends Config( class RV32RocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithRV32 ++ // set RocketTiles to be 32-bit new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -127,6 +141,7 @@ class RV32RocketConfig extends Config( class GB1MemoryRocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithExtMemSize((1<<30) * 1L) ++ // use 2GB simulated external memory new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -136,6 +151,7 @@ class GB1MemoryRocketConfig extends Config( class Sha3RocketConfig extends Config( new WithTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new sha3.WithSha3Accel ++ // add SHA3 rocc accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -147,6 +163,7 @@ class InitZeroRocketConfig extends Config( new WithInitZero(0x88000000L, 0x1000L) ++ new WithInitZeroTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -156,6 +173,7 @@ class LoopbackNICRocketConfig extends Config( new WithIceNIC ++ new WithLoopbackNICTop ++ new WithBootROM ++ + new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) diff --git a/generators/example/src/main/scala/TestHarness.scala b/generators/example/src/main/scala/TestHarness.scala index 292d1bd1..3eaa05e2 100644 --- a/generators/example/src/main/scala/TestHarness.scala +++ b/generators/example/src/main/scala/TestHarness.scala @@ -47,6 +47,7 @@ class TestHarness(implicit val p: Parameters) extends Module { axi.w.bits := DontCare } }) + dut.connectSimUARTs() io.success := dut.connectSimSerial() } diff --git a/generators/example/src/main/scala/Top.scala b/generators/example/src/main/scala/Top.scala index 586ec990..defb4ef4 100644 --- a/generators/example/src/main/scala/Top.scala +++ b/generators/example/src/main/scala/Top.scala @@ -13,6 +13,7 @@ import testchipip._ import utilities.{System, SystemModule} import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.uart._ import icenet.{HasPeripheryIceNIC, HasPeripheryIceNICModuleImp} @@ -22,13 +23,15 @@ import icenet.{HasPeripheryIceNIC, HasPeripheryIceNICModuleImp} class Top(implicit p: Parameters) extends System with HasNoDebug - with HasPeripherySerial { + with HasPeripherySerial + with CanHavePeripheryUARTWithAdapter { override lazy val module = new TopModule(this) } class TopModule[+L <: Top](l: L) extends SystemModule(l) with HasNoDebugModuleImp with HasPeripherySerialModuleImp + with CanHavePeripheryUARTWithAdapterImp with DontTouch //--------------------------------------------------------------------------------------------------------- diff --git a/generators/testchipip b/generators/testchipip index 64408599..db01ac15 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 64408599a055f3f7cc6b2a90ae617e67b179b332 +Subproject commit db01ac1514d68fe55af2eb8f5bffb52da596ed75 From 612f1d5a104684ad901408c35f97c39d14aeff46 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 16 Jan 2020 11:47:31 -0800 Subject: [PATCH 40/75] Update LICENSE [ci skip] (#379) --- LICENSE | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/LICENSE b/LICENSE index c6092e14..946eca94 100644 --- a/LICENSE +++ b/LICENSE @@ -1,27 +1,30 @@ -Copyright (c) 2017-2019, The Regents of the University of California (Regents). +BSD 3-Clause License + +Copyright (c) 2017-2020, The Regents of the University of California (Regents) All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. -3. Neither the name of the Regents nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. -IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, -SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING -OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS -BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED -HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE -MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. From 1786b9a7f4752a42bf4ff4af7953ba570d636945 Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Tue, 21 Jan 2020 15:19:54 -0800 Subject: [PATCH 41/75] Don't check prebuilt tools are on master (#384) Backport from #362 h/t @jerryz123 --- .circleci/check-commit.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/check-commit.sh b/.circleci/check-commit.sh index 873b241e..3c57d64c 100755 --- a/.circleci/check-commit.sh +++ b/.circleci/check-commit.sh @@ -64,7 +64,7 @@ branches=("master") search -submodules=("riscv-gnu-toolchain" "riscv-isa-sim" "riscv-pk" "riscv-tests" "riscv-gnu-toolchain-prebuilt") +submodules=("riscv-gnu-toolchain" "riscv-isa-sim" "riscv-pk" "riscv-tests") dir="toolchains/riscv-tools" branches=("master") search From ac5235e5ed6225b6fb5d8f00a45d035a0e53cf2a Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Tue, 21 Jan 2020 20:44:54 -0800 Subject: [PATCH 42/75] Revamp the config system for Top/Harness (#347) * Refactor how Configs parameterize the Top and TestHarnesses * Bump sha3, testchipip, icenet, firesim --- .circleci/defaults.sh | 2 +- docs/Advanced-Concepts/CDEs.rst | 111 ++++++++ docs/Advanced-Concepts/index.rst | 2 + docs/Chipyard-Basics/index.rst | 1 + docs/Customization/Adding-An-Accelerator.rst | 261 ------------------ docs/Customization/Custom-Chisel.rst | 59 ++++ docs/Customization/DMA-Devices.rst | 39 +++ .../Incorporating-Verilog-Blocks.rst | 51 +--- docs/Customization/Keys-Traits-Configs.rst | 106 +++++++ docs/Customization/MMIO-Peripherals.rst | 142 ++++++++++ docs/Customization/RoCC-Accelerators.rst | 70 +++++ docs/Customization/RoCC-or-MMIO.rst | 27 ++ docs/Customization/index.rst | 31 ++- docs/Generators/Gemmini.rst | 2 +- docs/Generators/SHA3.rst | 2 +- docs/Generators/SiFive-Generators.rst | 10 +- docs/Quick-Start.rst | 2 +- .../src/main/resources/vsrc/GCDMMIOBlackBox.v | 4 +- .../example/src/main/scala/BoomConfigs.scala | 46 ++- .../example/src/main/scala/ConfigMixins.scala | 151 ++++------ generators/example/src/main/scala/GCD.scala | 200 ++++++++++++++ .../src/main/scala/GCDMMIOBlackBox.scala | 98 ------- .../src/main/scala/HeteroConfigs.scala | 45 ++- .../example/src/main/scala/InitZero.scala | 16 +- generators/example/src/main/scala/PWM.scala | 134 --------- .../src/main/scala/RocketConfigs.scala | 117 +++++--- .../example/src/main/scala/TestHarness.scala | 57 +--- generators/example/src/main/scala/Top.scala | 108 ++------ .../src/main/scala/BridgeBinders.scala | 10 +- .../src/main/scala/TargetConfigs.scala | 12 +- .../firechip/src/main/scala/Targets.scala | 21 +- generators/icenet | 2 +- generators/sha3 | 2 +- generators/testchipip | 2 +- sims/firesim | 2 +- 35 files changed, 1087 insertions(+), 858 deletions(-) create mode 100644 docs/Advanced-Concepts/CDEs.rst delete mode 100644 docs/Customization/Adding-An-Accelerator.rst create mode 100644 docs/Customization/Custom-Chisel.rst create mode 100644 docs/Customization/DMA-Devices.rst create mode 100644 docs/Customization/Keys-Traits-Configs.rst create mode 100644 docs/Customization/MMIO-Peripherals.rst create mode 100644 docs/Customization/RoCC-Accelerators.rst create mode 100644 docs/Customization/RoCC-or-MMIO.rst create mode 100644 generators/example/src/main/scala/GCD.scala delete mode 100644 generators/example/src/main/scala/GCDMMIOBlackBox.scala delete mode 100644 generators/example/src/main/scala/PWM.scala diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index 87a761d9..c5838a48 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -45,7 +45,7 @@ mapping["example"]="SUB_PROJECT=example" mapping["boomrocketexample"]="SUB_PROJECT=example CONFIG=LargeBoomAndRocketConfig" mapping["boom"]="SUB_PROJECT=example CONFIG=SmallBoomConfig" mapping["rocketchip"]="SUB_PROJECT=rocketchip" -mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=SimBlockDeviceRocketConfig TOP=TopWithBlockDevice" +mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=SimBlockDeviceRocketConfig" mapping["hwacha"]="SUB_PROJECT=example CONFIG=HwachaRocketConfig" mapping["gemmini"]="SUB_PROJECT=example CONFIG=GemminiRocketConfig" mapping["tracegen"]="SUB_PROJECT=tracegen CONFIG=NonBlockingTraceGenL2Config" diff --git a/docs/Advanced-Concepts/CDEs.rst b/docs/Advanced-Concepts/CDEs.rst new file mode 100644 index 00000000..b8e130e6 --- /dev/null +++ b/docs/Advanced-Concepts/CDEs.rst @@ -0,0 +1,111 @@ +.. _cdes: + +Context-Dependent-Environments +======================================== + +Readers may notice that the parameterization system frequently uses ``(site, here, up)``. +This construct is an artifact of the "context-dependent-environment" system which Chipyard and Rocket Chip both leverage for powerful composable hardware configuration. + +The CDE parameterization system provides different "Views" of a single global parameterization. The syntax for accessing a ``Field`` within a ``View`` is ``my_view(MyKey, site_view)``, where ``site_view`` is a "global" view that will be passed recursively into various functions and key-lookups in the call-stack of ``my_view(MyKey, site_view)``. + +.. note:: + Rocket Chip based designs will frequently use ``val p: Parameters`` and ``p(SomeKey)`` to lookup the value of a key. ``Parameters`` is just a subclass of the ``View`` abstract class, and ``p(SomeKey)`` really expands into ``p(SomeKey, p)``. This is because we consider the call ``p(SomeKey)`` to be the "site", or "source" of the original key query, so we need to pass in the view of the configuration provided by ``p`` recursively to future calls through the ``site`` argument. + +Consider the following example using CDEs. + +.. code:: scala + + case object SomeKeyX extends Field[Boolean](false) // default is false + case object SomeKeyY extends Field[Boolean](false) // default is false + case object SomeKeyZ extends Field[Boolean](false) // default is false + + class WithX(b: Boolean) extends Config((site, here, up) => { + case SomeKeyX => b + } + + class WithY(b: Boolean) extends Config((site, here, up) => { + case SomeKeyY => b + } + + +When forming a query based on a ``Parameters`` object, like ``p(SomeKeyX)``, the configuration system traverses the "chain" of mixins until it finds a partial function which is defined at the key, and then returns that value. + +.. code:: scala + + val params = Config(new WithX(true) ++ new WithY(true)) // "chain" together mixins + params(SomeKeyX) // evaluates to true + params(SomeKeyY) // evaluates to true + params(SomeKeyZ) // evaluates to false + +In this example, the evaluation of ``params(SomeKeyX)`` will terminate in the partial function defined in ``WithX(true)``, while the evaluation of ``params(SomeKeyY)`` will terminate in the partial function defined in ``WithY(true)``. Note that when no partial functions match, the evaluation will return the default value for that parameter. + +The real power of CDEs arises from the ``(site, here, up)`` parameters to the partial functions, which provide useful "views" into the global parameterization that the partial functions may access to determine a parameterization. + +.. note:: + Additional information on the motivations for CDEs can be found in Chapter 2 of `Henry Cook's Thesis `_ . + + +Site +~~~~ + +``site`` provides a ``View`` of the "source" of the original parameter query. + +.. code:: scala + + class WithXEqualsYSite extends Config((site, here, up) => { + case SomeKeyX => site(SomeKeyY) // expands to site(SomeKeyY, site) + } + + val params_1 = Config(new WithXEqualsYSite ++ new WithY(true)) + val params_2 = Config(new WithY(true) ++ new WithXEqualsYSite) + params_1(SomeKeyX) // evaluates to true + params_2(SomeKeyX) // evaluates to true + + +In this example, the partial function in ``WithXEqualsYSite`` will look up the value of ``SomeKeyY`` in the original ``params_N`` object, which becomes ``site`` in each call in the recursive traversal. + + +Here +~~~~ + +``here`` provides a ``View`` of the locally defined Config, which typically just contains some partial function. + +.. code:: scala + + class WithXEqualsYHere extends Config((site, here, up) => { + case SomeKeyY => false + case SomeKeyX => here(SomeKeyY, site) + } + + val params_1 = Config(new WithXEqualsYHere ++ new WithY(true)) + val params_2 = Config(new WithY(true) ++ new WithXEqualsYHere) + + params_1(SomeKeyX) // evaluates to false + params_2(SomeKeyX) // evaluates to false + +In this example, note that although our final parameterization in ``params_2`` has ``SomeKeyY`` set to ``true``, the call to ``here(SomeKeyY, site)`` only looks in the local partial function defined in ``WithXEqualsYHere``. Note that we pass ``site`` to ``here`` since ``site`` may be used in the recursive call. + + +Up +~~~~ + +``up`` provides a ``View`` of the previously defined set of partial functions in the "chain" of partial functions. This is useful when we want to lookup a previously set value for some key, but not the final value for that key. + +.. code:: scala + + class WithXEqualsYUp extends Config((site, here, up) => { + case SomeKeyX => up(SomeKeyY, site) + } + + val params_1 = Config(new WithXEqualsYUp ++ new WithY(true)) + val params_2 = Config(new WithY(true) ++ new WithXEqualsYUp) + + params_1(SomeKeyX) // evaluates to true + params_2(SomeKeyX) // evaluates to false + +In this example, note how ``up(SomeKeyY, site)`` in ``WithXEqualsYUp`` will refer to *either* the the partial function defining ``SomeKeyY`` in ``WithY(true)`` *or* the default value for ``SomeKeyY`` provided in the original ``case object SomeKeyY`` definition, *depending on the order in which the mixins were used*. Since the order of mixins affects the the order of the ``View`` traversal, ``up`` provides a different ``View`` of the parameterization in ``params_1`` and ``params_2``. + + +Also note that again, ``site`` must be recursively passed through the call to ``up``. + + diff --git a/docs/Advanced-Concepts/index.rst b/docs/Advanced-Concepts/index.rst index 8194fe1f..af23525a 100644 --- a/docs/Advanced-Concepts/index.rst +++ b/docs/Advanced-Concepts/index.rst @@ -12,3 +12,5 @@ They expect you to know about Chisel, Parameters, Configs, etc. Chip-Communication Debugging-RTL Resources + CDEs + diff --git a/docs/Chipyard-Basics/index.rst b/docs/Chipyard-Basics/index.rst index 28a08700..9a306c4f 100644 --- a/docs/Chipyard-Basics/index.rst +++ b/docs/Chipyard-Basics/index.rst @@ -16,6 +16,7 @@ Hit next to get started! :caption: Chipyard Basics: Chipyard-Components + Development-Ecosystem Configs-Parameters-Mixins Initial-Repo-Setup diff --git a/docs/Customization/Adding-An-Accelerator.rst b/docs/Customization/Adding-An-Accelerator.rst deleted file mode 100644 index 3c0ea4eb..00000000 --- a/docs/Customization/Adding-An-Accelerator.rst +++ /dev/null @@ -1,261 +0,0 @@ -.. _adding-an-accelerator: - -Adding an Accelerator/Device -=============================== - -Accelerators or custom IO devices can be added to your SoC in several ways: - -* MMIO Peripheral (a.k.a TileLink-Attached Accelerator) -* Tightly-Coupled RoCC Accelerator - -These approaches differ in the method of the communication between the processor and the custom block. - -With the TileLink-Attached approach, the processor communicates with MMIO peripherals through memory-mapped registers. - -In contrast, the processor communicates with a RoCC accelerators through a custom protocol and custom non-standard ISA instructions reserved in the RISC-V ISA encoding space. -Each core can have up to four accelerators that are controlled by custom instructions and share resources with the CPU. -RoCC coprocessor instructions have the following form. - -.. code-block:: none - - customX rd, rs1, rs2, funct - -The X will be a number 0-3, and determines the opcode of the instruction, which controls which accelerator an instruction will be routed to. -The ``rd``, ``rs1``, and ``rs2`` fields are the register numbers of the destination register and two source registers. -The ``funct`` field is a 7-bit integer that the accelerator can use to distinguish different instructions from each other. - -Note that communication through a RoCC interface requires a custom software toolchain, whereas MMIO peripherals can use that standard toolchain with appropriate driver support. - -Integrating into the Generator Build System -------------------------------------------- - -While developing, you want to include Chisel code in a submodule so that it can be shared by different projects. -To add a submodule to the Chipyard framework, make sure that your project is organized as follows. - -.. code-block:: none - - yourproject/ - build.sbt - src/main/scala/ - YourFile.scala - -Put this in a git repository and make it accessible. -Then add it as a submodule to under the following directory hierarchy: ``generators/yourproject``. - -.. code-block:: shell - - cd generators/ - git submodule add https://git-repository.com/yourproject.git - -Then add ``yourproject`` to the Chipyard top-level build.sbt file. - -.. code-block:: scala - - lazy val yourproject = (project in file("generators/yourproject")).settings(commonSettings).dependsOn(rocketchip) - -You can then import the classes defined in the submodule in a new project if -you add it as a dependency. For instance, if you want to use this code in -the ``example`` project, change the final line in build.sbt to the following. - -.. code-block:: scala - - lazy val example = (project in file(".")).settings(commonSettings).dependsOn(testchipip, yourproject) - -MMIO Peripheral ------------------- - -The easiest way to create a TileLink peripheral is to use the ``TLRegisterRouter``, which abstracts away the details of handling the TileLink protocol and provides a convenient interface for specifying memory-mapped registers. -To create a RegisterRouter-based peripheral, you will need to specify a parameter case class for the configuration settings, a bundle trait with the extra top-level ports, and a module implementation containing the actual RTL. -In this case we use a submodule ``PWMBase`` to actually perform the pulse-width modulation. The ``PWMModule`` class only creates the registers and hooks them -up using ``regmap``. - -.. literalinclude:: ../../generators/example/src/main/scala/PWM.scala - :language: scala - :start-after: DOC include start: PWM generic traits - :end-before: DOC include end: PWM generic traits - -Once you have these classes, you can construct the final peripheral by extending the ``TLRegisterRouter`` and passing the proper arguments. -The first set of arguments determines where the register router will be placed in the global address map and what information will be put in its device tree entry. -The second set of arguments is the IO bundle constructor, which we create by extending ``TLRegBundle`` with our bundle trait. -The final set of arguments is the module constructor, which we create by extends ``TLRegModule`` with our module trait. - -.. literalinclude:: ../../generators/example/src/main/scala/PWM.scala - :language: scala - :start-after: DOC include start: PWMTL - :end-before: DOC include end: PWMTL - -The full module code can be found in ``generators/example/src/main/scala/PWM.scala``. - -After creating the module, we need to hook it up to our SoC. -Rocket Chip accomplishes this using the cake pattern. -This basically involves placing code inside traits. -In the Rocket Chip cake, there are two kinds of traits: a ``LazyModule`` trait and a module implementation trait. - -The ``LazyModule`` trait runs setup code that must execute before all the hardware gets elaborated. -For a simple memory-mapped peripheral, this just involves connecting the peripheral's TileLink node to the MMIO crossbar. - -.. literalinclude:: ../../generators/example/src/main/scala/PWM.scala - :language: scala - :start-after: DOC include start: HasPeripheryPWMTL - :end-before: DOC include end: HasPeripheryPWMTL - -Note that the ``PWMTL`` class we created from the register router is itself a ``LazyModule``. -Register routers have a TileLink node simply named "node", which we can hook up to the Rocket Chip bus. -This will automatically add address map and device tree entries for the peripheral. - -The module implementation trait is where we instantiate our PWM module and connect it to the rest of the SoC. -Since this module has an extra `pwmout` output, we declare that in this trait, using Chisel's multi-IO functionality. -We then connect the ``PWMTL``'s pwmout to the pwmout we declared. - -.. literalinclude:: ../../generators/example/src/main/scala/PWM.scala - :language: scala - :start-after: DOC include start: HasPeripheryPWMTLModuleImp - :end-before: DOC include end: HasPeripheryPWMTLModuleImp - -Now we want to mix our traits into the system as a whole. -This code is from ``generators/example/src/main/scala/Top.scala``. - -.. literalinclude:: ../../generators/example/src/main/scala/Top.scala - :language: scala - :start-after: DOC include start: TopWithPWMTL - :end-before: DOC include end: TopWithPWMTL - -Just as we need separate traits for ``LazyModule`` and module implementation, we need two classes to build the system. -The ``Top`` classes already have the basic peripherals included for us, so we will just extend those. - -The ``Top`` class includes the pre-elaboration code and also a ``lazy val`` to produce the module implementation (hence ``LazyModule``). -The ``TopModule`` class is the actual RTL that gets synthesized. - -Next, we need to add a configuration mixin in ``generators/example/src/main/scala/ConfigMixins.scala`` that tells the ``TestHarness`` to instantiate ``TopWithPWMTL`` instead of the default ``Top``. - -.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala - :language: scala - :start-after: DOC include start: WithPWMTop - :end-before: DOC include end: WithPWMTop - -And finally, we create a configuration class in ``generators/example/src/main/scala/Configs.scala`` that uses this mixin. - -.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala - :language: scala - :start-after: DOC include start: PWMRocketConfig - :end-before: DOC include end: PWMRocketConfig - -Now we can test that the PWM is working. The test program is in ``tests/pwm.c``. - -.. literalinclude:: ../../tests/pwm.c - :language: c - -This just writes out to the registers we defined earlier. -The base of the module's MMIO region is at 0x2000. -This will be printed out in the address map portion when you generated the verilog code. - -Compiling this program with make produces a ``pwm.riscv`` executable. - -Now with all of that done, we can go ahead and run our simulation. - -.. code-block:: shell - - cd sims/verilator - make CONFIG=PWMRocketConfig TOP=TopWithPWMTL - ./simulator-example-PWMRocketConfig ../../tests/pwm.riscv - -Adding a RoCC Accelerator ----------------------------- - -RoCC accelerators are lazy modules that extend the ``LazyRoCC`` class. -Their implementation should extends the ``LazyRoCCModule`` class. - -.. code-block:: scala - - class CustomAccelerator(opcodes: OpcodeSet) - (implicit p: Parameters) extends LazyRoCC(opcodes) { - override lazy val module = new CustomAcceleratorModule(this) - } - - class CustomAcceleratorModule(outer: CustomAccelerator) - extends LazyRoCCModuleImp(outer) { - val cmd = Queue(io.cmd) - // The parts of the command are as follows - // inst - the parts of the instruction itself - // opcode - // rd - destination register number - // rs1 - first source register number - // rs2 - second source register number - // funct - // xd - is the destination register being used? - // xs1 - is the first source register being used? - // xs2 - is the second source register being used? - // rs1 - the value of source register 1 - // rs2 - the value of source register 2 - ... - } - - -The ``opcodes`` parameter for ``LazyRoCC`` is the set of custom opcodes that will map to this accelerator. -More on this in the next subsection. - -The ``LazyRoCC`` class contains two TLOutputNode instances, ``atlNode`` and ``tlNode``. -The former connects into a tile-local arbiter along with the backside of the L1 instruction cache. -The latter connects directly to the L1-L2 crossbar. -The corresponding Tilelink ports in the module implementation's IO bundle are ``atl`` and ``tl``, respectively. - -The other interfaces available to the accelerator are ``mem``, which provides access to the L1 cache; -``ptw`` which provides access to the page-table walker; -the ``busy`` signal, which indicates when the accelerator is still handling an instruction; -and the ``interrupt`` signal, which can be used to interrupt the CPU. - -Look at the examples in ``generators/rocket-chip/src/main/scala/tile/LazyRocc.scala`` for detailed information on the different IOs. - -Adding RoCC accelerator to Config -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -RoCC accelerators can be added to a core by overriding the ``BuildRoCC`` parameter in the configuration. -This takes a sequence of functions producing ``LazyRoCC`` objects, one for each accelerator you wish to add. - -For instance, if we wanted to add the previously defined accelerator and route custom0 and custom1 instructions to it, we could do the following. - -.. code-block:: scala - - class WithCustomAccelerator extends Config((site, here, up) => { - case BuildRoCC => Seq((p: Parameters) => LazyModule( - new CustomAccelerator(OpcodeSet.custom0 | OpcodeSet.custom1)(p))) - }) - - class CustomAcceleratorConfig extends Config( - new WithCustomAccelerator ++ new RocketConfig) - -To add RoCC instructions in your program, use the RoCC C macros provided in ``tests/rocc.h``. You can find examples in the files ``tests/accum.c`` and ``charcount.c``. - -Adding a DMA port -------------------- - -For IO devices or accelerators (like a disk or network driver), instead of -having the CPU poll data from the device, we may want to have the device write -directly to the coherent memory system instead. For example, here is a device -that writes zeros to the memory at a configured address. - -.. literalinclude:: ../../generators/example/src/main/scala/InitZero.scala - :language: scala - -.. literalinclude:: ../../generators/example/src/main/scala/Top.scala - :language: scala - :start-after: DOC include start: TopWithInitZero - :end-before: DOC include end: TopWithInitZero - -We use ``TLHelper.makeClientNode`` to create a TileLink client node for us. -We then connect the client node to the memory system through the front bus (fbus). -For more info on creating TileLink client nodes, take a look at :ref:`Client Node`. - -Once we've created our top-level module including the DMA widget, we can create a configuration for it as we did before. - -.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala - :language: scala - :start-after: DOC include start: WithInitZero - :end-before: DOC include end: WithInitZero - -.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala - :language: scala - :start-after: DOC include start: InitZeroRocketConfig - :end-before: DOC include end: InitZeroRocketConfig - - diff --git a/docs/Customization/Custom-Chisel.rst b/docs/Customization/Custom-Chisel.rst new file mode 100644 index 00000000..feec3141 --- /dev/null +++ b/docs/Customization/Custom-Chisel.rst @@ -0,0 +1,59 @@ +.. _custom_chisel: + +Integrating Custom Chisel Projects into the Generator Build System +================================================================== + +.. warning:: + This section assumes integration of custom Chisel through git submodules. + While it is possible to directly commit custom Chisel into the Chipyard framework, + we heavily recommend managing custom code through git submodules. Using submodules decouples + development of custom features from development on the Chipyard framework. + + +While developing, you want to include Chisel code in a submodule so that it can be shared by different projects. +To add a submodule to the Chipyard framework, make sure that your project is organized as follows. + +.. code-block:: none + + yourproject/ + build.sbt + src/main/scala/ + YourFile.scala + +Put this in a git repository and make it accessible. +Then add it as a submodule to under the following directory hierarchy: ``generators/yourproject``. + +The ``build.sbt`` is a minimal file which describes metadata for a Chisel project. +For a simple project, the ``build.sbt`` can even be empty, but below we provide an example +build.sbt. + +.. code-block:: scala + + organization := "edu.berkeley.cs" + + version := "1.0" + + name := "yourproject" + + scalaVersion := "2.12.4" + + + +.. code-block:: shell + + cd generators/ + git submodule add https://git-repository.com/yourproject.git + +Then add ``yourproject`` to the Chipyard top-level build.sbt file. + +.. code-block:: scala + + lazy val yourproject = (project in file("generators/yourproject")).settings(commonSettings).dependsOn(rocketchip) + +You can then import the classes defined in the submodule in a new project if +you add it as a dependency. For instance, if you want to use this code in +the ``example`` project, change the final line in build.sbt to the following. + +.. code-block:: scala + + lazy val example = (project in file(".")).settings(commonSettings).dependsOn(testchipip, yourproject) diff --git a/docs/Customization/DMA-Devices.rst b/docs/Customization/DMA-Devices.rst new file mode 100644 index 00000000..f2e95e52 --- /dev/null +++ b/docs/Customization/DMA-Devices.rst @@ -0,0 +1,39 @@ +.. _dma-devices: + +Adding a DMA Device +=================== + +DMA devices are Tilelink widgets which act as masters. In other words, +DMA devices can send their own read and write requests to the chip's memory +system. + +For IO devices or accelerators (like a disk or network driver), instead of +having the CPU poll data from the device, we may want to have the device write +directly to the coherent memory system instead. For example, here is a device +that writes zeros to the memory at a configured address. + +.. literalinclude:: ../../generators/example/src/main/scala/InitZero.scala + :language: scala + +.. literalinclude:: ../../generators/example/src/main/scala/Top.scala + :language: scala + :start-after: DOC include start: Top + :end-before: DOC include end: Top + +We use ``TLHelper.makeClientNode`` to create a TileLink client node for us. +We then connect the client node to the memory system through the front bus (fbus). +For more info on creating TileLink client nodes, take a look at :ref:`Client Node`. + +Once we've created our top-level module including the DMA widget, we can create a configuration for it as we did before. + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: WithInitZero + :end-before: DOC include end: WithInitZero + +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala + :language: scala + :start-after: DOC include start: InitZeroRocketConfig + :end-before: DOC include end: InitZeroRocketConfig + + diff --git a/docs/Customization/Incorporating-Verilog-Blocks.rst b/docs/Customization/Incorporating-Verilog-Blocks.rst index 64f064f8..48f0c6e3 100644 --- a/docs/Customization/Incorporating-Verilog-Blocks.rst +++ b/docs/Customization/Incorporating-Verilog-Blocks.rst @@ -8,8 +8,7 @@ design flows. Fortunately, both Chisel and Chipyard provide extensive support for Verilog integration. Here, we will examine the process of incorporating an MMIO peripheral -(similar to the PWM example from the previous section) that uses a -Verilog implementation of Greatest Common Denominator (GCD) +that uses a Verilog implementation of Greatest Common Denominator (GCD) algorithm. There are a few steps to adding a Verilog peripheral: * Adding a Verilog resource file to the project @@ -58,7 +57,7 @@ and Verilog sources follow the prescribed directory layout. build.sbt src/main/ scala/ - GCDMMIOBlackBox.scala + GCD.scala resources/ vsrc/ GCDMMIOBlackBox.v @@ -89,7 +88,7 @@ as the bitwidth of the GCD calculation does in this example. **Chisel BlackBox Definition** -.. literalinclude:: ../../generators/example/src/main/scala/GCDMMIOBlackBox.scala +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala :language: scala :start-after: DOC include start: GCD blackbox :end-before: DOC include end: GCD blackbox @@ -102,54 +101,32 @@ diplomatic memory mapping on the system bus, we still have to integrate the peripheral at the Chisel level by mixing peripheral-specific traits into a ``TLRegisterRouter``. The ``params`` member and ``HasRegMap`` base trait should look familiar from the -previous memory-mapped PWM device example. +previous memory-mapped GCD device example. -.. literalinclude:: ../../generators/example/src/main/scala/GCDMMIOBlackBox.scala +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala :language: scala :start-after: DOC include start: GCD instance regmap :end-before: DOC include end: GCD instance regmap -Advanced Features of RegField Entries -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -One significant difference from the PWM example is in the peripheral's -memory map. ``RegField`` exposes polymorphic ``r`` and ``w`` methods -that allow read- and write-only memory-mapped registers to be -interfaced to hardware in multiple ways. - -* ``RegField.r(2, status)`` is used to create a 2-bit, read-only register that captures the current value of the ``status`` signal when read. -* ``RegField.r(params.width, gcd)`` "connects" the decoupled handshaking interface ``gcd`` to a read-only memory-mapped register. When this register is read via MMIO, the ``ready`` signal is asserted. This is in turn connected to ``output_ready`` on the Verilog blackbox through the glue logic. -* ``RegField.w(params.width, x)`` exposes a plain register (much like those in the PWM example) via MMIO, but makes it write-only. -* ``RegField.w(params.width, y)`` associates the decoupled interface signal ``y`` with a write-only memory-mapped register, causing ``y.valid`` to be asserted when the register is written. - -Since the ready/valid signals of ``y`` are connected to the -``input_ready`` and ``input_valid`` signals of the blackbox, -respectively, this register map and glue logic has the effect of -triggering the GCD algorithm when ``y`` is written. Therefore, the -algorithm is set up by first writing ``x`` and then performing a -triggering write to ``y``. Polling can be used for status checks. - -Defining a Chip with a GCD Peripheral +Defining a Chip with a BlackBox --------------------------------------- -As with the PWM example, a few more pieces are needed to tie the system together. +Since we've parameterized the GCD instantiation to choose between the +Chisel and the verilog module, creating a config is easy. -**Composing traits into a complete cake pattern peripheral** - -.. literalinclude:: ../../generators/example/src/main/scala/GCDMMIOBlackBox.scala +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala :language: scala - :start-after: DOC include start: GCD cake - :end-before: DOC include end: GCD cake + :start-after: DOC include start: GCDAXI4BlackBoxRocketConfig + :end-before: DOC include end: GCDAXI4BlackBoxRocketConfig -Note the differences arising due to the fact that this peripheral has -no top-level IO. To build a complete system, a new ``Top`` and new -``Config`` objects are added in a manner exactly analogous to the PWM -example. +You can play with the parameterization of the mixin to choose a TL/AXI4, BlackBox/Chisel +version of the GCD. Software Testing ---------------- -The GCD module has a slightly more complex interface, so polling is +The GCD module has a more complex interface, so polling is used to check the status of the device before each triggering read or write. diff --git a/docs/Customization/Keys-Traits-Configs.rst b/docs/Customization/Keys-Traits-Configs.rst new file mode 100644 index 00000000..8184975f --- /dev/null +++ b/docs/Customization/Keys-Traits-Configs.rst @@ -0,0 +1,106 @@ +.. _keys-traits-configs: + +Keys, Traits, and Configs +========================= + +You have probably seen snippets of Chisel referencing Keys, Traits, and Configs by this point. +This section aims to elucidate the interactions between these Chisel/Scala components, and provide +best practices for how these should be used to create a parameterized design and configure it. + +We will continue to use the GCD example. + +Keys +---- + +Keys specify some parameter which controls some custom widget. Keys should typically be implemented as **Option types**, with a default value of ``None`` that means no change in the system. In other words, the default behavior when the user does not explicitly set the key should be a no-op. + +Keys should be defined and documented in sub-projects, since they generally deal with some specific block, and not system-level integration. (We make an exception for the example GCD widget). + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD key + :end-before: DOC include end: GCD key + +The object within a key is typically a ``case class XXXParams``, which defines a set of parameters which some block accepts. For example, the GCD widget's ``GCDParams`` parameterizes its address, operand widths, whether the widget should be connected by Tilelink or AXI4, and whether the widget should use the blackbox-verilog implementation, or the Chisel implementation. + + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD params + :end-before: DOC include end: GCD params + +Accessing the value stored in the key is easy in Chisel, as long as the ``implicit p: Parameters`` object is being passed through to the relevant module. For example, ``p(GCDKey).get.address`` returns the address field of ``GCDParams``. Note this only works if ``GCDKey`` was not set to ``None``, so your Chisel should check for that case! + +Traits +------ + +Typically, most custom blocks will need to modify the behavior of some pre-existing block. For example, the GCD widget needs the ``Top`` module to instantiate and connect the widget via Tilelink, generate a top-level ``gcd_busy`` port, and connect that to the module as well. Traits let us do this without modifying the existing code for the ``Top``, and enables compartmentalization of code for different custom blocks. + +Top-level traits specify that the ``Top`` has been parameterized to read some custom Key and optionally instantiate and connect a widget defined by that Key. Traits **should not** mandate the instantiation of custom logic. In other words, traits should be written with ``CanHave`` semantics, where the default behavior when the Key is unset is a no-op. + +Top-level traits should be defined and documented in subprojects, alongside their corresponding Keys. The traits should then be added to the ``Top`` being used by Chipyard. + +Below we see the traits for the GCD example. The Lazy trait connects the GCD module to the Diplomacy graph, while the Implementation trait causes the ``Top`` to instantiate an additional port and concretely connect it to the GCD module. + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD lazy trait + :end-before: DOC include end: GCD imp trait + +These traits are added to the default ``Top`` in Chipyard. + +.. literalinclude:: ../../generators/example/src/main/scala/Top.scala + :language: scala + :start-after: DOC include start: Top + :end-before: DOC include end: Top + +Mixins +------ + +Mixins set the keys to a non-default value. Together, the collection of Mixins which define a configuration generate the values for all the keys used by the generator. + +For example, the ``WithGCDMixin`` is parameterized by the type of GCD widget you want to instantiate. When this mixin is added to a config, the ``GCDKey`` is set to a instance of ``GCDParams``, informing the previously mentioned traits to instantiate and connect the GCD widget appropriately. + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: GCD mixin + :end-before: DOC include end: GCD mixin + +We can use this mixin when composing our configs. + +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala + :language: scala + :start-after: DOC include start: GCDTLRocketConfig + :end-before: DOC include end: GCDTLRocketConfig + + +BuildTop +-------- + +The ``BuildTop`` key is special, because sometimes, we need to instantiate ``TestHarness`` modules to interface with a custom widget. The ``BuildTop`` key provides a function which can call some method of the Top to instantiate these ``TestHarness`` modules. Since the ``BuildTop`` key is called from the ``TestHarness``, these modules will appear in the ``TestHarness``. The config system also lets the ``BuildTop`` key look recursively into previous definitions of itself. This enables composability of the ``Top`` configurations. + +For example, conside a config that contains the mixins ``WithGPIO ++ WithTSI``. We need to instantiate the TSI serial adapter, and connect it to the ``success`` signal of our ``TestHarness``. We also need to instantiate the GPIO pins, and tie their inputs to 0 in the ``TestHarness``, since we currently cannot drive the GPIOs in simulation. + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: tsi mixin + :end-before: DOC include end: tsi mixin + + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: gpio mixin + :end-before: DOC include end: gpio mixin + +When ``WithGPIO ++ WithTSI`` is evaluated right to left, the call to ``up(BuildTop, site)`` in ``WithGPIO`` will reference the function defined in the ``BuildTop`` key of ``WithTSI``. Thus, at elaboration time, when the ``BuildTop`` function is called by the ``TestHarness``, first the ``BuildTop`` function in ``WithTSI`` will be evaluated. This connects the ``success`` signal of the ``TestHarness`` to the ``SerialAdapter`` enabled by ``WithTSI``. Then, the rest of the code in the ``BuildTop`` function of ``WithGPIO`` will execute, tieing off the top-level GPIO input pins. Thus the evaluation of the ``BuildTop`` functions in a completed config is "right-to-left", matching how the evaluation of the mixins at compile-time is also "right-to-left". + +.. warning:: + Note that in some cases, the ordering and duplication of mixins which extend ``BuildTop`` will have unintended consequences. + For example, ``WithTSI ++ WithTSI`` will attempt to generate and connect two ``SimSerial`` widgets in the ``TestHarness``, + which will likely break the simulation. + In general, you should avoid attaching multiple mixins which interface to the same top-level ports. + +.. note:: + Readers who want more information on the configuration system may be interested in reading :ref:`cdes`. + + diff --git a/docs/Customization/MMIO-Peripherals.rst b/docs/Customization/MMIO-Peripherals.rst new file mode 100644 index 00000000..0e01edb5 --- /dev/null +++ b/docs/Customization/MMIO-Peripherals.rst @@ -0,0 +1,142 @@ +.. _mmio-accelerators: + +MMIO Peripherals +================== + +The easiest way to create a MMIO peripheral is to use the ``TLRegisterRouter`` or ``AXI4RegisterRouter`` widgets, which abstracts away the details of handling the interconnect protocols and provides a convenient interface for specifying memory-mapped registers. Since Chipyard and Rocket Chip SoCs primarily use Tilelink as the on-chip interconnect protocol, this section will primarily focus on designing Tilelink-based peripherals. However, see ``generators/example/src/main/scala/GCD.scala`` for how an example AXI4 based peripheral is defined and connected to the Tilelink graph through converters. + +To create a RegisterRouter-based peripheral, you will need to specify a parameter case class for the configuration settings, a bundle trait with the extra top-level ports, and a module implementation containing the actual RTL. + +For this example, we will show how to connect a MMIO peripheral which computes the GCD. +The full code can be found in ``generators/example/src/main/scala/GCD.scala``. + +In this case we use a submodule ``GCDMMIOChiselModule`` to actually perform the GCD. The ``GCDModule`` class only creates the registers and hooks them up using ``regmap``. + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD chisel + :end-before: DOC include end: GCD chisel + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD instance regmap + :end-before: DOC include end: GCD instance regmap + +Advanced Features of RegField Entries +------------------------------------- + +``RegField`` exposes polymorphic ``r`` and ``w`` methods +that allow read- and write-only memory-mapped registers to be +interfaced to hardware in multiple ways. + +* ``RegField.r(2, status)`` is used to create a 2-bit, read-only register that captures the current value of the ``status`` signal when read. +* ``RegField.r(params.width, gcd)`` "connects" the decoupled handshaking interface ``gcd`` to a read-only memory-mapped register. When this register is read via MMIO, the ``ready`` signal is asserted. This is in turn connected to ``output_ready`` on the GCD module through the glue logic. +* ``RegField.w(params.width, x)`` exposes a plain register via MMIO, but makes it write-only. +* ``RegField.w(params.width, y)`` associates the decoupled interface signal ``y`` with a write-only memory-mapped register, causing ``y.valid`` to be asserted when the register is written. + +Since the ready/valid signals of ``y`` are connected to the +``input_ready`` and ``input_valid`` signals of the GCD module, +respectively, this register map and glue logic has the effect of +triggering the GCD algorithm when ``y`` is written. Therefore, the +algorithm is set up by first writing ``x`` and then performing a +triggering write to ``y``. Polling can be used for status checks. + + +Connecting by TileLink +---------------------- + +Once you have these classes, you can construct the final peripheral by extending the ``TLRegisterRouter`` and passing the proper arguments. +The first set of arguments determines where the register router will be placed in the global address map and what information will be put in its device tree entry. +The second set of arguments is the IO bundle constructor, which we create by extending ``TLRegBundle`` with our bundle trait. +The final set of arguments is the module constructor, which we create by extends ``TLRegModule`` with our module trait. +Notice how we can create an analogous AXI4 version of our peripheral. + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD router + :end-before: DOC include end: GCD router + + + +Top-level Traits +---------------- + +After creating the module, we need to hook it up to our SoC. +Rocket Chip accomplishes this using the cake pattern. +This basically involves placing code inside traits. +In the Rocket Chip cake, there are two kinds of traits: a ``LazyModule`` trait and a module implementation trait. + +The ``LazyModule`` trait runs setup code that must execute before all the hardware gets elaborated. +For a simple memory-mapped peripheral, this just involves connecting the peripheral's TileLink node to the MMIO crossbar. + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD lazy trait + :end-before: DOC include end: GCD lazy trait + +Note that the ``GCDTL`` class we created from the register router is itself a ``LazyModule``. +Register routers have a TileLink node simply named "node", which we can hook up to the Rocket Chip bus. +This will automatically add address map and device tree entries for the peripheral. +Also observe how we have to place additional AXI4 buffers and converters for the AXI4 version of this peripheral. + +For peripherals which instantiate a concrete module, or which need to be connected to concrete IOs or wires, a matching concrete trait is necessary. We will make our GCD example output a ``gcd_busy`` signal as a top-level port to demonstrate. In the concrete module implementation trait, we instantiate the top level IO (a concrete object) and wire it to the IO of our lazy module. + + +.. literalinclude:: ../../generators/example/src/main/scala/GCD.scala + :language: scala + :start-after: DOC include start: GCD imp trait + :end-before: DOC include end: GCD imp trait + +Constructing the Top and Config +------------------------------- + +Now we want to mix our traits into the system as a whole. +This code is from ``generators/example/src/main/scala/Top.scala``. + +.. literalinclude:: ../../generators/example/src/main/scala/Top.scala + :language: scala + :start-after: DOC include start: Top + :end-before: DOC include end: Top + +Just as we need separate traits for ``LazyModule`` and module implementation, we need two classes to build the system. +The ``Top`` class contains the set of traits which parameterize and define the ``Top``. Typically these traits will optionally add IOs or peripherals to the ``Top``. +The ``Top`` class includes the pre-elaboration code and also a ``lazy val`` to produce the module implementation (hence ``LazyModule``). +The ``TopModule`` class is the actual RTL that gets synthesized. + + + +And finally, we create a configuration class in ``generators/example/src/main/scala/Configs.scala`` that uses the ``WithGCD`` mixin defined earlier. + +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: GCD mixin + :end-before: DOC include end: GCD mixin + +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala + :language: scala + :start-after: DOC include start: GCDTLRocketConfig + :end-before: DOC include end: GCDTLRocketConfig + +Testing +------- + +Now we can test that the GCD is working. The test program is in ``tests/gcd.c``. + +.. literalinclude:: ../../tests/gcd.c + :language: c + +This just writes out to the registers we defined earlier. +The base of the module's MMIO region is at 0x2000 by default. +This will be printed out in the address map portion when you generate the verilog code. +You can also see how this changes the emitted ``.json`` addressmap files in ``generated-src``. + +Compiling this program with ``make`` produces a ``gcd.riscv`` executable. + +Now with all of that done, we can go ahead and run our simulation. + +.. code-block:: shell + + cd sims/verilator + make CONFIG=GCDTLRocketConfig BINARY=../../tests/gcd.riscv run-binary + + diff --git a/docs/Customization/RoCC-Accelerators.rst b/docs/Customization/RoCC-Accelerators.rst new file mode 100644 index 00000000..7a3f4447 --- /dev/null +++ b/docs/Customization/RoCC-Accelerators.rst @@ -0,0 +1,70 @@ +.. _rocc-accelerators: + +Adding a RoCC Accelerator +---------------------------- + +RoCC accelerators are lazy modules that extend the ``LazyRoCC`` class. +Their implementation should extends the ``LazyRoCCModule`` class. + +.. code-block:: scala + + class CustomAccelerator(opcodes: OpcodeSet) + (implicit p: Parameters) extends LazyRoCC(opcodes) { + override lazy val module = new CustomAcceleratorModule(this) + } + + class CustomAcceleratorModule(outer: CustomAccelerator) + extends LazyRoCCModuleImp(outer) { + val cmd = Queue(io.cmd) + // The parts of the command are as follows + // inst - the parts of the instruction itself + // opcode + // rd - destination register number + // rs1 - first source register number + // rs2 - second source register number + // funct + // xd - is the destination register being used? + // xs1 - is the first source register being used? + // xs2 - is the second source register being used? + // rs1 - the value of source register 1 + // rs2 - the value of source register 2 + ... + } + + +The ``opcodes`` parameter for ``LazyRoCC`` is the set of custom opcodes that will map to this accelerator. +More on this in the next subsection. + +The ``LazyRoCC`` class contains two TLOutputNode instances, ``atlNode`` and ``tlNode``. +The former connects into a tile-local arbiter along with the backside of the L1 instruction cache. +The latter connects directly to the L1-L2 crossbar. +The corresponding Tilelink ports in the module implementation's IO bundle are ``atl`` and ``tl``, respectively. + +The other interfaces available to the accelerator are ``mem``, which provides access to the L1 cache; +``ptw`` which provides access to the page-table walker; +the ``busy`` signal, which indicates when the accelerator is still handling an instruction; +and the ``interrupt`` signal, which can be used to interrupt the CPU. + +Look at the examples in ``generators/rocket-chip/src/main/scala/tile/LazyRocc.scala`` for detailed information on the different IOs. + +Adding RoCC accelerator to Config +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +RoCC accelerators can be added to a core by overriding the ``BuildRoCC`` parameter in the configuration. +This takes a sequence of functions producing ``LazyRoCC`` objects, one for each accelerator you wish to add. + +For instance, if we wanted to add the previously defined accelerator and route custom0 and custom1 instructions to it, we could do the following. + +.. code-block:: scala + + class WithCustomAccelerator extends Config((site, here, up) => { + case BuildRoCC => Seq((p: Parameters) => LazyModule( + new CustomAccelerator(OpcodeSet.custom0 | OpcodeSet.custom1)(p))) + }) + + class CustomAcceleratorConfig extends Config( + new WithCustomAccelerator ++ + new RocketConfig) + +To add RoCC instructions in your program, use the RoCC C macros provided in ``tests/rocc.h``. You can find examples in the files ``tests/accum.c`` and ``charcount.c``. + diff --git a/docs/Customization/RoCC-or-MMIO.rst b/docs/Customization/RoCC-or-MMIO.rst new file mode 100644 index 00000000..dd1ed81c --- /dev/null +++ b/docs/Customization/RoCC-or-MMIO.rst @@ -0,0 +1,27 @@ +.. _rocc-vs-mmio: + +RoCC vs MMIO +------------ + +Accelerators or custom IO devices can be added to your SoC in several ways: + +* MMIO Peripheral (a.k.a TileLink-Attached Accelerator) +* Tightly-Coupled RoCC Accelerator + +These approaches differ in the method of the communication between the processor and the custom block. + +With the TileLink-Attached approach, the processor communicates with MMIO peripherals through memory-mapped registers. + +In contrast, the processor communicates with a RoCC accelerators through a custom protocol and custom non-standard ISA instructions reserved in the RISC-V ISA encoding space. +Each core can have up to four accelerators that are controlled by custom instructions and share resources with the CPU. +RoCC coprocessor instructions have the following form. + +.. code-block:: none + + customX rd, rs1, rs2, funct + +The X will be a number 0-3, and determines the opcode of the instruction, which controls which accelerator an instruction will be routed to. +The ``rd``, ``rs1``, and ``rs2`` fields are the register numbers of the destination register and two source registers. +The ``funct`` field is a 7-bit integer that the accelerator can use to distinguish different instructions from each other. + +Note that communication through a RoCC interface requires a custom software toolchain, whereas MMIO peripherals can use that standard toolchain with appropriate driver support. diff --git a/docs/Customization/index.rst b/docs/Customization/index.rst index cd52a499..c76c1f3f 100644 --- a/docs/Customization/index.rst +++ b/docs/Customization/index.rst @@ -3,18 +3,41 @@ Customization These guides will walk you through customization of your system-on-chip: -- Contructing heterogenous systems-on-chip using the Chipyard generators and configuration system. +- Contructing heterogenous systems-on-chip using the existing Chipyard generators and configuration system. -- Adding custom accelerators to your system-on-chip. +- How to include your custom Chisel sources in the Chipyard build system -Hit next to get started! +- Adding custom RoCC accelerators to an existing Chipyard core (BOOM or Rocket) + +- Adding custom MMIO widgets to the Chipyard memory system by Tilelink or AXI4, with custom Top-level IOs + +- Standard practices for using Keys, Traits, and Configs to parameterize your design + +- Customizing the memory hierarchy + +- Connect widgets which act as TileLink masters + +- Adding custom blackboxed verilog to a Chipyard design + +We also provide information on: + +- The boot process for Chipyard SoCs + +- Examples of FIRRTL transforms used in Chipyard, and where they are specified + +We recommend reading all these pages in order. Hit next to get started! .. toctree:: :maxdepth: 2 :caption: Customization: Heterogeneous-SoCs - Adding-An-Accelerator + Custom-Chisel + RoCC-or-MMIO + RoCC-Accelerators + MMIO-Peripherals + Keys-Traits-Configs + DMA-Devices Incorporating-Verilog-Blocks Memory-Hierarchy Boot-Process diff --git a/docs/Generators/Gemmini.rst b/docs/Generators/Gemmini.rst index d90e6224..66f8e017 100644 --- a/docs/Generators/Gemmini.rst +++ b/docs/Generators/Gemmini.rst @@ -56,7 +56,7 @@ The ``software`` directory of the generator includes the aforementioned library The Gemmini generator generates a C header file based on the generator parameters. This header files gets compiled together with the matrix multiplication library to tune library performance. The generated header file can be found under ``software/gemmini-rocc-tests/include/gemmini_params.h`` Build and Run Gemmini Tests -^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^ To build Gemmini tests: diff --git a/docs/Generators/SHA3.rst b/docs/Generators/SHA3.rst index a61e7e82..a9b87108 100644 --- a/docs/Generators/SHA3.rst +++ b/docs/Generators/SHA3.rst @@ -78,6 +78,6 @@ this mixin is shown here: :end-before: DOC include end: Sha3Rocket The SHA3 example baremetal and Linux tests are located in the SHA3 repository. -Please refer to its `README.md`__ for more information on how to run/build the tests. +Please refer to its `README.md `_ for more information on how to run/build the tests. diff --git a/docs/Generators/SiFive-Generators.rst b/docs/Generators/SiFive-Generators.rst index 8f2202b0..19360162 100644 --- a/docs/Generators/SiFive-Generators.rst +++ b/docs/Generators/SiFive-Generators.rst @@ -20,17 +20,11 @@ To integrate one of these devices in your SoC, you will need to define a custom .. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala :language: scala - :start-after: DOC include start: WithGPIO - :end-before: DOC include end: WithGPIO + :start-after: DOC include start: gpio mixin + :end-before: DOC include end: gpio mixin Additionally, if the device requires top-level IOs, you will need to define a mixin to change the top-level configuration of your SoC. When adding a top-level IO, you should also be aware of whether it interacts with the test-harness. -For example, a GPIO device would require a GPIO pin, and therefore we would write a mixin to augment the top level as follows: - -.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala - :language: scala - :start-after: DOC include start: WithGPIOTop - :end-before: DOC include end: WithGPIOTop This example instantiates a top-level module with include GPIO ports (``TopWithGPIO``), and then ties-off the GPIO port inputs to 0 (``false.B``). diff --git a/docs/Quick-Start.rst b/docs/Quick-Start.rst index d1d7ed93..cc650bd6 100644 --- a/docs/Quick-Start.rst +++ b/docs/Quick-Start.rst @@ -54,7 +54,7 @@ This depends on what you are planning to do with Chipyard. * If you intend to run a full-system FireSim simulation, go to :ref:`firesim-sim-intro` and follow the instructions. -* If you intend to add a new accelerator, go to :ref:`adding-an-accelerator` and follow the instructions. +* If you intend to add a new accelerator, go to :ref:`customization` and follow the instructions. * If you want to learn about the structure of Chipyard, go to :ref:`chipyard-components`. diff --git a/generators/example/src/main/resources/vsrc/GCDMMIOBlackBox.v b/generators/example/src/main/resources/vsrc/GCDMMIOBlackBox.v index 9104ae87..46acd5c8 100644 --- a/generators/example/src/main/resources/vsrc/GCDMMIOBlackBox.v +++ b/generators/example/src/main/resources/vsrc/GCDMMIOBlackBox.v @@ -10,7 +10,8 @@ module GCDMMIOBlackBox input [WIDTH-1:0] y, input output_ready, output output_valid, - output reg [WIDTH-1:0] gcd + output reg [WIDTH-1:0] gcd, + output busy ); // DOC include end: GCD portlist @@ -21,6 +22,7 @@ module GCDMMIOBlackBox assign input_ready = state == S_IDLE; assign output_valid = state == S_DONE; + assign busy = state != S_IDLE; always @(posedge clock) begin if (reset) diff --git a/generators/example/src/main/scala/BoomConfigs.scala b/generators/example/src/main/scala/BoomConfigs.scala index 0f1535ea..a6a0adb4 100644 --- a/generators/example/src/main/scala/BoomConfigs.scala +++ b/generators/example/src/main/scala/BoomConfigs.scala @@ -9,54 +9,72 @@ import freechips.rocketchip.config.{Config} // --------------------- class SmallBoomConfig extends Config( - new WithTop ++ // use normal top + new WithTSI ++ // use testchipip serial offchip link + new WithNoGPIO ++ // no top-level GPIO pins (overrides default set in sifive-blocks) new WithBootROM ++ // use testchipip bootrom new WithUART ++ // add a UART + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level mmio master port (overrides default set in rocketchip) + new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level mmio slave port (overrides default set in rocketchip) new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use SiFive L2 cache new boom.common.WithSmallBooms ++ // 1-wide BOOM new boom.common.WithNBoomCores(1) ++ // single-core new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system class MediumBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithMediumBooms ++ // 2-wide BOOM new boom.common.WithNBoomCores(1) ++ new freechips.rocketchip.system.BaseConfig) class LargeBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithLargeBooms ++ // 3-wide BOOM new boom.common.WithNBoomCores(1) ++ new freechips.rocketchip.system.BaseConfig) class MegaBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithMegaBooms ++ // 4-wide BOOM new boom.common.WithNBoomCores(1) ++ new freechips.rocketchip.system.BaseConfig) class DualSmallBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithSmallBooms ++ new boom.common.WithNBoomCores(2) ++ // dual-core new freechips.rocketchip.system.BaseConfig) class SmallRV32BoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithoutBoomFPU ++ // no fp new boom.common.WithBoomRV32 ++ // rv32 (32bit) @@ -65,9 +83,12 @@ class SmallRV32BoomConfig extends Config( new freechips.rocketchip.system.BaseConfig) class HwachaLargeBoomConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator new boom.common.WithLargeBooms ++ // 3-wide BOOM @@ -75,11 +96,16 @@ class HwachaLargeBoomConfig extends Config( new freechips.rocketchip.system.BaseConfig) class LoopbackNICBoomConfig extends Config( - new WithIceNIC ++ - new WithLoopbackNICTop ++ + new WithTSI ++ + new WithNoGPIO ++ + new WithLoopbackNIC ++ // loopback the NIC + new WithIceNIC ++ // add IceNIC new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new boom.common.WithLargeBooms ++ // 3-wide BOOM + new boom.common.WithLargeBooms ++ new boom.common.WithNBoomCores(1) ++ new freechips.rocketchip.system.BaseConfig) + diff --git a/generators/example/src/main/scala/ConfigMixins.scala b/generators/example/src/main/scala/ConfigMixins.scala index 441a9289..b3deeb3f 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -7,8 +7,10 @@ import freechips.rocketchip.config.{Field, Parameters, Config} import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, WithRoccExample, WithNMemoryChannels, WithNBigCores, WithRV32, CacheBlockBytes} import freechips.rocketchip.diplomacy.{LazyModule, ValName} import freechips.rocketchip.devices.tilelink.BootROMParams -import freechips.rocketchip.tile.{RocketTileParams, MaxHartIdBits, XLen, BuildRoCC, TileKey, LazyRoCC} +import freechips.rocketchip.devices.debug.{Debug} +import freechips.rocketchip.tile.{XLen, BuildRoCC, TileKey, LazyRoCC, RocketTileParams, MaxHartIdBits} import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams, ICacheParams} +import freechips.rocketchip.util.{AsyncResetReg} import boom.common.{BoomTilesKey} @@ -33,23 +35,30 @@ import ConfigValName._ // Common Parameter Mixins // ----------------------- -/** - * Class to specify where the BootRom file is (from `rebar` top) - */ class WithBootROM extends Config((site, here, up) => { case BootROMParams => BootROMParams( contentFileName = s"./bootrom/bootrom.rv${site(XLen)}.img") }) -// DOC include start: WithGPIO -/** - * Class to add in GPIO - */ +// DOC include start: gpio mixin class WithGPIO extends Config((site, here, up) => { case PeripheryGPIOKey => Seq( GPIOParams(address = 0x10012000, width = 4, includeIOF = false)) + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) + // TODO: Currently FIRRTL will error if the GPIO input + // pins are unconnected, so tie them to 0. + // In future IO cell blackboxes will replace this with + // more correct functionality + for (gpio <- top.gpio) { + for (pin <- gpio.pins) { + pin.i.ival := false.B + } + } + top + } }) -// DOC include end: WithGPIO +// DOC include end: gpio mixin /** * Class to add in UART @@ -59,92 +68,58 @@ class WithUART extends Config((site, here, up) => { UARTParams(address = 0x54000000L, nTxEntries = 256, nRxEntries = 256)) }) -// ----------------------------------------------- -// BOOM and/or Rocket Top Level System Parameter Mixins -// ----------------------------------------------- -/** - * Class to specify a "plain" top level BOOM and/or Rocket system - */ -class WithTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - Module(LazyModule(new Top()(p)).module) +class WithNoGPIO extends Config((site, here, up) => { + case PeripheryGPIOKey => Seq() +}) + +// DOC include start: tsi mixin +class WithTSI extends Config((site, here, up) => { + case SerialKey => true + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) + success := top.connectSimSerial() + top + } +}) +// DOC include end: tsi mixin + +class WithDTM extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) + top.reset := reset.asBool | top.debug.map { debug => AsyncResetReg(debug.ndreset) }.getOrElse(false.B) + Debug.connectDebug(top.debug, top.psd, clock, reset.asBool, success)(p) + top } }) -/** - * Class to specify a top level BOOM and/or Rocket system with DTM - */ -class WithDTMTop extends Config((site, here, up) => { - case BuildTopWithDTM => (clock: Clock, reset: Bool, p: Parameters) => { - Module(LazyModule(new TopWithDTM()(p)).module) - } +// DOC include start: GCD mixin +class WithGCD(useAXI4: Boolean, useBlackBox: Boolean) extends Config((site, here, up) => { + case GCDKey => Some(GCDParams(useAXI4 = useAXI4, useBlackBox = useBlackBox)) }) +// DOC include end: GCD mixin -/** - * Class to specify a top level BOOM and/or Rocket system with PWM - */ -// DOC include start: WithPWMTop -class WithPWMTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new TopWithPWMTL()(p)).module) -}) -// DOC include end: WithPWMTop - -/** - * Class to specify a top level BOOM and/or Rocket system with a PWM AXI4 - */ -class WithPWMAXI4Top extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new TopWithPWMAXI4()(p)).module) -}) - -/** - * Class to specify a top level BOOM and/or Rocket system with a TL-attached GCD device - */ -class WithGCDTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new TopWithGCD()(p)).module) -}) - -/** - * Class to specify a top level BOOM and/or Rocket system with a block device - */ -class WithBlockDeviceModelTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new TopWithBlockDevice()(p)).module) +class WithBlockDeviceModel extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) top.connectBlockDeviceModel() top } }) -/** - * Class to specify a top level BOOM and/or Rocket system with a simulator block device - */ -class WithSimBlockDeviceTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new TopWithBlockDevice()(p)).module) +class WithSimBlockDevice extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) top.connectSimBlockDevice(clock, reset) top } }) -// DOC include start: WithGPIOTop -/** - * Class to specify a top level BOOM and/or Rocket system with GPIO - */ -class WithGPIOTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new TopWithGPIO()(p)).module) - for (gpio <- top.gpio) { - for (pin <- gpio.pins) { - pin.i.ival := false.B - } - } - top - } +// DOC include start: WithInitZero +class WithInitZero(base: BigInt, size: BigInt) extends Config((site, here, up) => { + case InitZeroKey => Some(InitZeroConfig(base, size)) }) -// DOC include end: WithGPIOTop +// DOC include end: WithInitZero // ------------------ // Multi-RoCC Support @@ -184,16 +159,6 @@ class WithMultiRoCCHwacha(harts: Int*) extends Config((site, here, up) => { } }) -// DOC include start: WithInitZero -class WithInitZero(base: BigInt, size: BigInt) extends Config((site, here, up) => { - case InitZeroKey => InitZeroConfig(base, size) -}) - -class WithInitZeroTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new TopWithInitZero()(p)).module) -}) -// DOC include end: WithInitZero /** * Mixin to add a small Rocket core to the system as a "control" core. @@ -227,15 +192,15 @@ class WithControlCore extends Config((site, here, up) => { class WithIceNIC(inBufFlits: Int = 1800, usePauser: Boolean = false) extends Config((site, here, up) => { - case NICKey => NICConfig( + case NICKey => Some(NICConfig( inBufFlits = inBufFlits, usePauser = usePauser, - checksumOffload = true) + checksumOffload = true)) }) -class WithLoopbackNICTop extends Config((site, here, up) => { - case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new TopWithIceNIC()(p)).module) +class WithLoopbackNIC extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = up(BuildTop, site)(clock, reset, p, success) top.connectNicLoopback() top } diff --git a/generators/example/src/main/scala/GCD.scala b/generators/example/src/main/scala/GCD.scala new file mode 100644 index 00000000..f41e78db --- /dev/null +++ b/generators/example/src/main/scala/GCD.scala @@ -0,0 +1,200 @@ +package example + +import chisel3._ +import chisel3.util._ +import chisel3.experimental.{IntParam, BaseModule} +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.config.{Parameters, Field} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.regmapper.{HasRegMap, RegField} +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.UIntIsOneOf + +// DOC include start: GCD params +case class GCDParams( + address: BigInt = 0x2000, + width: Int = 32, + useAXI4: Boolean = false, + useBlackBox: Boolean = true) +// DOC include end: GCD params + +// DOC include start: GCD key +case object GCDKey extends Field[Option[GCDParams]](None) +// DOC include end: GCD key + +class GCDIO(val w: Int) extends Bundle { + val clock = Input(Clock()) + val reset = Input(Bool()) + val input_ready = Output(Bool()) + val input_valid = Input(Bool()) + val x = Input(UInt(w.W)) + val y = Input(UInt(w.W)) + val output_ready = Input(Bool()) + val output_valid = Output(Bool()) + val gcd = Output(UInt(w.W)) + val busy = Output(Bool()) +} + +trait GCDTopIO extends Bundle { + val gcd_busy = Output(Bool()) +} + +trait HasGCDIO extends BaseModule { + val w: Int + val io = IO(new GCDIO(w)) +} + +// DOC include start: GCD blackbox +class GCDMMIOBlackBox(val w: Int) extends BlackBox(Map("WIDTH" -> IntParam(w))) with HasBlackBoxResource + with HasGCDIO +{ + addResource("/vsrc/GCDMMIOBlackBox.v") +} +// DOC include end: GCD blackbox + +// DOC include start: GCD chisel +class GCDMMIOChiselModule(val w: Int) extends Module + with HasGCDIO +{ + val s_idle :: s_run :: s_done :: Nil = Enum(3) + + val state = RegInit(s_idle) + val tmp = Reg(UInt(w.W)) + val gcd = Reg(UInt(w.W)) + + io.input_ready := state === s_idle + io.output_valid := state === s_done + io.gcd := gcd + + when (state === s_idle && io.input_valid) { + state := s_run + } .elsewhen (state === s_run && tmp === 0.U) { + state := s_done + } .elsewhen (state === s_done && io.output_ready) { + state := s_idle + } + + when (state === s_idle && io.input_valid) { + gcd := io.x + tmp := io.y + } .elsewhen (state === s_run) { + when (gcd > tmp) { + gcd := gcd - tmp + } .otherwise { + tmp := tmp - gcd + } + } + + io.busy := state =/= s_idle +} +// DOC include end: GCD chisel + +// DOC include start: GCD instance regmap + +trait GCDModule extends HasRegMap { + val io: GCDTopIO + + implicit val p: Parameters + def params: GCDParams + val clock: Clock + val reset: Reset + + + // How many clock cycles in a PWM cycle? + val x = Reg(UInt(params.width.W)) + val y = Wire(new DecoupledIO(UInt(params.width.W))) + val gcd = Wire(new DecoupledIO(UInt(params.width.W))) + val status = Wire(UInt(2.W)) + + val impl = if (params.useBlackBox) { + Module(new GCDMMIOBlackBox(params.width)) + } else { + Module(new GCDMMIOChiselModule(params.width)) + } + + impl.io.clock := clock + impl.io.reset := reset.asBool + + impl.io.x := x + impl.io.y := y.bits + impl.io.input_valid := y.valid + y.ready := impl.io.input_ready + + gcd.bits := impl.io.gcd + gcd.valid := impl.io.output_valid + impl.io.output_ready := gcd.ready + + status := Cat(impl.io.input_ready, impl.io.output_ready) + io.gcd_busy := impl.io.busy + + regmap( + 0x00 -> Seq( + RegField.r(2, status)), // a read-only register capturing current status + 0x04 -> Seq( + RegField.w(params.width, x)), // a plain, write-only register + 0x08 -> Seq( + RegField.w(params.width, y)), // write-only, y.valid is set on write + 0x0C -> Seq( + RegField.r(params.width, gcd))) // read-only, gcd.ready is set on read +} +// DOC include end: GCD instance regmap + +// DOC include start: GCD router +class GCDTL(params: GCDParams, beatBytes: Int)(implicit p: Parameters) + extends TLRegisterRouter( + params.address, "gcd", Seq("ucbbar,gcd"), + beatBytes = beatBytes)( + new TLRegBundle(params, _) with GCDTopIO)( + new TLRegModule(params, _, _) with GCDModule) + +class GCDAXI4(params: GCDParams, beatBytes: Int)(implicit p: Parameters) + extends AXI4RegisterRouter( + params.address, + beatBytes=beatBytes)( + new AXI4RegBundle(params, _) with GCDTopIO)( + new AXI4RegModule(params, _, _) with GCDModule) +// DOC include end: GCD router + +// DOC include start: GCD lazy trait +trait CanHavePeripheryGCD { this: BaseSubsystem => + private val portName = "gcd" + + // Only build if we are using the TL (nonAXI4) version + val gcd = p(GCDKey) match { + case Some(params) => { + if (params.useAXI4) { + val gcd = LazyModule(new GCDAXI4(params, pbus.beatBytes)(p)) + pbus.toSlave(Some(portName)) { + gcd.node := + AXI4Buffer () := + TLToAXI4 () := + // toVariableWidthSlave doesn't use holdFirstDeny, which TLToAXI4() needsx + TLFragmenter(pbus.beatBytes, pbus.blockBytes, holdFirstDeny = true) + } + Some(gcd) + } else { + val gcd = LazyModule(new GCDTL(params, pbus.beatBytes)(p)) + pbus.toVariableWidthSlave(Some(portName)) { gcd.node } + Some(gcd) + } + } + case None => None + } +} +// DOC include end: GCD lazy trait + +// DOC include start: GCD imp trait +trait CanHavePeripheryGCDModuleImp extends LazyModuleImp { + val outer: CanHavePeripheryGCD + val gcd_busy = outer.gcd match { + case Some(gcd) => { + val busy = IO(Output(Bool())) + busy := gcd.module.io.gcd_busy + Some(busy) + } + case None => None + } +} + +// DOC include end: GCD imp trait diff --git a/generators/example/src/main/scala/GCDMMIOBlackBox.scala b/generators/example/src/main/scala/GCDMMIOBlackBox.scala deleted file mode 100644 index 891fe1c9..00000000 --- a/generators/example/src/main/scala/GCDMMIOBlackBox.scala +++ /dev/null @@ -1,98 +0,0 @@ -package example - -import chisel3._ -import chisel3.util._ -import chisel3.core.{IntParam, Reset} -import freechips.rocketchip.amba.axi4._ -import freechips.rocketchip.subsystem.BaseSubsystem -import freechips.rocketchip.config.{Parameters, Field} -import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.regmapper.{HasRegMap, RegField} -import freechips.rocketchip.tilelink._ -import freechips.rocketchip.util.UIntIsOneOf - -// DOC include start: GCD blackbox -class GCDMMIOBlackBox(w: Int) extends BlackBox(Map("WIDTH" -> IntParam(w))) with HasBlackBoxResource { - val io = IO(new Bundle { - val clock = Input(Clock()) - val reset = Input(Bool()) - val input_ready = Output(Bool()) - val input_valid = Input(Bool()) - val x = Input(UInt(w.W)) - val y = Input(UInt(w.W)) - val output_ready = Input(Bool()) - val output_valid = Output(Bool()) - val gcd = Output(UInt(w.W)) - }) - - addResource("/vsrc/GCDMMIOBlackBox.v") -} -// DOC include end: GCD blackbox - -// DOC include start: GCD instance regmap -case class GCDParams(address: BigInt, beatBytes: Int, width: Int) - -trait GCDModule extends HasRegMap { - implicit val p: Parameters - def params: GCDParams - val clock: Clock - val reset: Reset - - val impl = Module(new GCDMMIOBlackBox(params.width)) - - // How many clock cycles in a PWM cycle? - val x = Reg(UInt(params.width.W)) - val y = Wire(new DecoupledIO(impl.io.y)) - val gcd = Wire(new DecoupledIO(impl.io.gcd)) - val status = Cat(impl.io.input_ready, impl.io.output_valid) - - impl.io.clock := clock - impl.io.reset := reset.asBool - impl.io.x := x - impl.io.y := y.bits - impl.io.input_valid := y.valid - y.ready := impl.io.input_ready - - gcd.bits := impl.io.gcd - gcd.valid := impl.io.output_valid - impl.io.output_ready := gcd.ready - - regmap( - 0x00 -> Seq( - RegField.r(2, status)), // a read-only register capturing current status - 0x04 -> Seq( - RegField.w(params.width, x)), // a plain, write-only register - 0x08 -> Seq( - RegField.w(params.width, y)), // write-only, y.valid is set on write - 0x0C -> Seq( - RegField.r(params.width, gcd))) // read-only, gcd.ready is set on read -} -// DOC include end: GCD instance regmap - -// DOC include start: GCD cake -class GCD(c: GCDParams)(implicit p: Parameters) - extends TLRegisterRouter( - c.address, "gcd", Seq("ucbbar,gcd"), - beatBytes = c.beatBytes)( - new TLRegBundle(c, _))( - new TLRegModule(c, _, _) with GCDModule) - -trait HasPeripheryGCD { this: BaseSubsystem => - implicit val p: Parameters - - private val address = 0x2000 - private val portName = "gcd" - private val gcdWidth = 32 - - val gcd = LazyModule(new GCD( - GCDParams(address, pbus.beatBytes, gcdWidth))(p)) - - pbus.toVariableWidthSlave(Some(portName)) { gcd.node } -} - -trait HasPeripheryGCDModuleImp extends LazyModuleImp { - implicit val p: Parameters - val outer: HasPeripheryGCD -} - -// DOC include end: GCD cake diff --git a/generators/example/src/main/scala/HeteroConfigs.scala b/generators/example/src/main/scala/HeteroConfigs.scala index e5cebef9..d68532ad 100644 --- a/generators/example/src/main/scala/HeteroConfigs.scala +++ b/generators/example/src/main/scala/HeteroConfigs.scala @@ -9,10 +9,13 @@ import freechips.rocketchip.config.{Config} // --------------------- class LargeBoomAndRocketConfig extends Config( - new WithTop ++ // default top + new WithTSI ++ // use testchipip serial offchip link + new WithNoGPIO ++ // no top-level GPIO pins (overrides default set in sifive-blocks) new WithBootROM ++ // default bootrom new WithUART ++ // add a UART new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use SiFive l2 + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip) + new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip) new boom.common.WithRenumberHarts ++ // avoid hartid overlap new boom.common.WithLargeBooms ++ // 3-wide boom new boom.common.WithNBoomCores(1) ++ // single-core boom @@ -20,10 +23,13 @@ class LargeBoomAndRocketConfig extends Config( new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system class SmallBoomAndRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new boom.common.WithRenumberHarts ++ new boom.common.WithSmallBooms ++ // 1-wide boom new boom.common.WithNBoomCores(1) ++ @@ -32,11 +38,14 @@ class SmallBoomAndRocketConfig extends Config( // DOC include start: BoomAndRocketWithHwacha class HwachaLargeBoomAndHwachaRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new hwacha.DefaultHwachaConfig ++ // add hwacha to all harts new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ new boom.common.WithNBoomCores(1) ++ @@ -45,10 +54,13 @@ class HwachaLargeBoomAndHwachaRocketConfig extends Config( // DOC include end: BoomAndRocketWithHwacha class RoccLargeBoomAndRoccRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithRoccExample ++ // add example rocc accelerator to all harts + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ @@ -57,9 +69,12 @@ class RoccLargeBoomAndRoccRocketConfig extends Config( new freechips.rocketchip.system.BaseConfig) class DualLargeBoomAndRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ @@ -69,10 +84,13 @@ class DualLargeBoomAndRocketConfig extends Config( // DOC include start: DualBoomAndRocketOneHwacha class DualLargeBoomAndHwachaRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new WithMultiRoCC ++ // support heterogeneous rocc new WithMultiRoCCHwacha(2) ++ // put hwacha on hart-2 (rocket) new boom.common.WithRenumberHarts ++ @@ -83,10 +101,13 @@ class DualLargeBoomAndHwachaRocketConfig extends Config( // DOC include end: DualBoomAndRocketOneHwacha class LargeBoomAndRV32RocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ new boom.common.WithNBoomCores(1) ++ @@ -96,10 +117,13 @@ class LargeBoomAndRV32RocketConfig extends Config( // DOC include start: DualBoomAndRocket class DualLargeBoomAndDualRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ new boom.common.WithNBoomCores(2) ++ // 2 boom cores @@ -108,10 +132,13 @@ class DualLargeBoomAndDualRocketConfig extends Config( // DOC include end: DualBoomAndRocket class MultiCoreWithControlCoreConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new WithControlCore ++ // add small control core (last hartid) new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ diff --git a/generators/example/src/main/scala/InitZero.scala b/generators/example/src/main/scala/InitZero.scala index 3a90bfcc..4c7f3bbb 100644 --- a/generators/example/src/main/scala/InitZero.scala +++ b/generators/example/src/main/scala/InitZero.scala @@ -8,7 +8,7 @@ import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, IdRange} import testchipip.TLHelper case class InitZeroConfig(base: BigInt, size: BigInt) -case object InitZeroKey extends Field[InitZeroConfig] +case object InitZeroKey extends Field[Option[InitZeroConfig]](None) class InitZero(implicit p: Parameters) extends LazyModule { val node = TLHelper.makeClientNode( @@ -18,7 +18,7 @@ class InitZero(implicit p: Parameters) extends LazyModule { } class InitZeroModuleImp(outer: InitZero) extends LazyModuleImp(outer) { - val config = p(InitZeroKey) + val config = p(InitZeroKey).get val (mem, edge) = outer.node.out(0) val addrBits = edge.bundle.addressBits @@ -57,13 +57,11 @@ class InitZeroModuleImp(outer: InitZero) extends LazyModuleImp(outer) { } } -trait HasPeripheryInitZero { this: BaseSubsystem => +trait CanHavePeripheryInitZero { this: BaseSubsystem => implicit val p: Parameters - val initZero = LazyModule(new InitZero()(p)) - fbus.fromPort(Some("init-zero"))() := initZero.node -} - -trait HasPeripheryInitZeroModuleImp extends LazyModuleImp { - // Don't need anything here + p(InitZeroKey) .map { k => + val initZero = LazyModule(new InitZero()(p)) + fbus.fromPort(Some("init-zero"))() := initZero.node + } } diff --git a/generators/example/src/main/scala/PWM.scala b/generators/example/src/main/scala/PWM.scala deleted file mode 100644 index bd6056f4..00000000 --- a/generators/example/src/main/scala/PWM.scala +++ /dev/null @@ -1,134 +0,0 @@ -package example - -import chisel3._ -import chisel3.util._ -import freechips.rocketchip.amba.axi4._ -import freechips.rocketchip.subsystem.BaseSubsystem -import freechips.rocketchip.config.{Parameters, Field} -import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.regmapper.{HasRegMap, RegField} -import freechips.rocketchip.tilelink._ -import freechips.rocketchip.util.UIntIsOneOf - -// DOC include start: PWM generic traits -case class PWMParams(address: BigInt, beatBytes: Int) - -class PWMBase(w: Int) extends Module { - val io = IO(new Bundle { - val pwmout = Output(Bool()) - val period = Input(UInt(w.W)) - val duty = Input(UInt(w.W)) - val enable = Input(Bool()) - }) - - // The counter should count up until period is reached - val counter = Reg(UInt(w.W)) - - when (counter >= (io.period - 1.U)) { - counter := 0.U - } .otherwise { - counter := counter + 1.U - } - - // If PWM is enabled, pwmout is high when counter < duty - // If PWM is not enabled, it will always be low - io.pwmout := io.enable && (counter < io.duty) -} - -trait PWMBundle extends Bundle { - val pwmout = Output(Bool()) -} - -trait PWMModule extends HasRegMap { - val io: PWMBundle - implicit val p: Parameters - def params: PWMParams - - // How many clock cycles in a PWM cycle? - val period = Reg(UInt(32.W)) - // For how many cycles should the clock be high? - val duty = Reg(UInt(32.W)) - // Is the PWM even running at all? - val enable = RegInit(false.B) - - val base = Module(new PWMBase(32)) - io.pwmout := base.io.pwmout - base.io.period := period - base.io.duty := duty - base.io.enable := enable - - regmap( - 0x00 -> Seq( - RegField(32, period)), - 0x04 -> Seq( - RegField(32, duty)), - 0x08 -> Seq( - RegField(1, enable))) -} -// DOC include end: PWM generic traits - -// DOC include start: PWMTL -class PWMTL(c: PWMParams)(implicit p: Parameters) - extends TLRegisterRouter( - c.address, "pwm", Seq("ucbbar,pwm"), - beatBytes = c.beatBytes)( - new TLRegBundle(c, _) with PWMBundle)( - new TLRegModule(c, _, _) with PWMModule) -// DOC include end: PWMTL - -class PWMAXI4(c: PWMParams)(implicit p: Parameters) - extends AXI4RegisterRouter(c.address, beatBytes = c.beatBytes)( - new AXI4RegBundle(c, _) with PWMBundle)( - new AXI4RegModule(c, _, _) with PWMModule) - -// DOC include start: HasPeripheryPWMTL -trait HasPeripheryPWMTL { this: BaseSubsystem => - implicit val p: Parameters - - private val address = 0x2000 - private val portName = "pwm" - - val pwm = LazyModule(new PWMTL( - PWMParams(address, pbus.beatBytes))(p)) - - pbus.toVariableWidthSlave(Some(portName)) { pwm.node } -} -// DOC include end: HasPeripheryPWMTL - -// DOC include start: HasPeripheryPWMTLModuleImp -trait HasPeripheryPWMTLModuleImp extends LazyModuleImp { - implicit val p: Parameters - val outer: HasPeripheryPWMTL - - val pwmout = IO(Output(Bool())) - - pwmout := outer.pwm.module.io.pwmout -} -// DOC include end: HasPeripheryPWMTLModuleImp - -trait HasPeripheryPWMAXI4 { this: BaseSubsystem => - implicit val p: Parameters - - private val address = 0x2000 - private val portName = "pwm" - - val pwm = LazyModule(new PWMAXI4( - PWMParams(address, pbus.beatBytes))(p)) - - pbus.toSlave(Some(portName)) { - pwm.node := - AXI4Buffer () := - TLToAXI4() := - // toVariableWidthSlave doesn't use holdFirstDeny, which TLToAXI4() needs - TLFragmenter(pbus.beatBytes, pbus.blockBytes, holdFirstDeny = true) - } -} - -trait HasPeripheryPWMAXI4ModuleImp extends LazyModuleImp { - implicit val p: Parameters - val outer: HasPeripheryPWMAXI4 - - val pwmout = IO(Output(Bool())) - - pwmout := outer.pwm.module.io.pwmout -} diff --git a/generators/example/src/main/scala/RocketConfigs.scala b/generators/example/src/main/scala/RocketConfigs.scala index edd18a36..4ccc2fd4 100644 --- a/generators/example/src/main/scala/RocketConfigs.scala +++ b/generators/example/src/main/scala/RocketConfigs.scala @@ -9,17 +9,23 @@ import freechips.rocketchip.config.{Config} // -------------- class RocketConfig extends Config( - new WithTop ++ // use default top + new WithTSI ++ // use testchipip serial offchip link + new WithNoGPIO ++ // no top-level GPIO pins (overrides default set in sifive-blocks) new WithBootROM ++ // use default bootrom new WithUART ++ // add a UART + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip) + new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip) new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system class HwachaRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -27,9 +33,12 @@ class HwachaRocketConfig extends Config( // DOC include start: GemminiRocketConfig class GemminiRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new gemmini.DefaultGemminiConfig ++ // use Gemmini systolic array GEMM accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -37,9 +46,12 @@ class GemminiRocketConfig extends Config( // DOC include end: GemminiRocketConfig class RoccRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithRoccExample ++ // use example RoCC-based accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -47,10 +59,13 @@ class RoccRocketConfig extends Config( // DOC include start: JtagRocket class jtagRocketConfig extends Config( - new WithDTMTop ++ // use top with dtm - new freechips.rocketchip.subsystem.WithJtagDTM ++ // add jtag+DTM module to coreplex + new WithDTM ++ // use top with dtm + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithJtagDTM ++ // enable communicating with the DTM using jtag + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) @@ -58,100 +73,127 @@ class jtagRocketConfig extends Config( // DOC include start: DmiRocket class dmiRocketConfig extends Config( - new WithDTMTop ++ // use top with dtm + new WithDTM ++ // use top with dtm + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include end: DmiRocket -// DOC include start: PWMRocketConfig -class PWMRocketConfig extends Config( - new WithPWMTop ++ // use top with tilelink-controlled PWM - new WithBootROM ++ +// DOC include start: GCDTLRocketConfig +class GCDTLRocketConfig extends Config( + new WithTSI ++ + new WithNoGPIO ++ new WithUART ++ + new WithGCD(useAXI4=false, useBlackBox=false) ++ // Use GCD Chisel, connect Tilelink + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) -// DOC include end: PWMRocketConfig +// DOC include end: GCDTLRocketConfig -class PWMAXI4RocketConfig extends Config( - new WithPWMAXI4Top ++ // use top with axi4-controlled PWM - new WithBootROM ++ - new WithUART ++ - new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.system.BaseConfig) - -class GCDRocketConfig extends Config( // add MMIO GCD module - new WithGCDTop ++ - new WithBootROM ++ +// DOC include start: GCDAXI4BlackBoxRocketConfig +class GCDAXI4BlackBoxRocketConfig extends Config( + new WithTSI ++ new WithUART ++ + new WithNoGPIO ++ + new WithGCD(useAXI4=true, useBlackBox=true) ++ // Use GCD blackboxed verilog, connect by AXI4->Tilelink + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) +// DOC include end: GCDAXI4BlackBoxRocketConfig class SimBlockDeviceRocketConfig extends Config( + new WithTSI ++ + new WithNoGPIO ++ new testchipip.WithBlockDevice ++ // add block-device module to peripherybus - new WithSimBlockDeviceTop ++ // use top with block-device IOs and connect to simblockdevice + new WithSimBlockDevice ++ // use top with block-device IOs and connect to simblockdevice new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) class BlockDeviceModelRocketConfig extends Config( + new WithTSI ++ + new WithNoGPIO ++ new testchipip.WithBlockDevice ++ // add block-device module to periphery bus - new WithBlockDeviceModelTop ++ // use top with block-device IOs and connect to a blockdevicemodel + new WithBlockDeviceModel ++ // use top with block-device IOs and connect to a blockdevicemodel new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include start: GPIORocketConfig class GPIORocketConfig extends Config( + new WithTSI ++ new WithGPIO ++ // add GPIOs to the peripherybus - new WithGPIOTop ++ // use top with GPIOs new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include end: GPIORocketConfig class DualCoreRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ new WithBootROM ++ new WithUART ++ + new WithNoGPIO ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(2) ++ // dual-core (2 RocketTiles) new freechips.rocketchip.system.BaseConfig) class RV32RocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithRV32 ++ // set RocketTiles to be 32-bit new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) class GB1MemoryRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithExtMemSize((1<<30) * 1L) ++ // use 2GB simulated external memory + new freechips.rocketchip.subsystem.WithExtMemSize((1<<30) * 1L) ++ // use 1GB simulated external memory new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include start: Sha3Rocket class Sha3RocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new sha3.WithSha3Accel ++ // add SHA3 rocc accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -160,20 +202,27 @@ class Sha3RocketConfig extends Config( // DOC include start: InitZeroRocketConfig class InitZeroRocketConfig extends Config( - new WithInitZero(0x88000000L, 0x1000L) ++ - new WithInitZeroTop ++ + new WithInitZero(0x88000000L, 0x1000L) ++ // add InitZero + new WithNoGPIO ++ + new WithTSI ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) // DOC include end: InitZeroRocketConfig class LoopbackNICRocketConfig extends Config( + new WithTSI ++ new WithIceNIC ++ - new WithLoopbackNICTop ++ + new WithNoGPIO ++ + new WithLoopbackNIC ++ new WithBootROM ++ new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) diff --git a/generators/example/src/main/scala/TestHarness.scala b/generators/example/src/main/scala/TestHarness.scala index 3eaa05e2..50c872f2 100644 --- a/generators/example/src/main/scala/TestHarness.scala +++ b/generators/example/src/main/scala/TestHarness.scala @@ -10,12 +10,22 @@ import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.util.GeneratorApp import freechips.rocketchip.devices.debug.{Debug} +/** + * TODO: Why do we need this? + */ +import ConfigValName._ + // ------------------------------- // BOOM and/or Rocket Test Harness // ------------------------------- -case object BuildTop extends Field[(Clock, Bool, Parameters) => TopModule[Top]] -case object BuildTopWithDTM extends Field[(Clock, Bool, Parameters) => TopWithDTMModule[TopWithDTM]] +case object BuildTop extends Field[(Clock, Bool, Parameters, Bool) => TopModule[Top]]( + (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { + val top = Module(LazyModule(new Top()(p)).suggestName("top").module) + top.debug.map { debug => debug := DontCare } + top + } +) /** * Test harness using TSI to bringup the system @@ -25,48 +35,8 @@ class TestHarness(implicit val p: Parameters) extends Module { val success = Output(Bool()) }) - // force Chisel to rename module - override def desiredName = "TestHarness" - - val dut = p(BuildTop)(clock, reset.toBool, p) - - dut.debug.foreach(_ := DontCare) - dut.connectSimAXIMem() - dut.connectSimAXIMMIO() - dut.dontTouchPorts() - dut.tieOffInterrupts() - dut.l2_frontend_bus_axi4.foreach(axi => { - axi.tieoff() - experimental.DataMirror.directionOf(axi.ar.ready) match { - case core.ActualDirection.Input => - axi.r.bits := DontCare - axi.b.bits := DontCare - case core.ActualDirection.Output => - axi.aw.bits := DontCare - axi.ar.bits := DontCare - axi.w.bits := DontCare - } - }) + val dut = p(BuildTop)(clock, reset.toBool, p, io.success) dut.connectSimUARTs() - - io.success := dut.connectSimSerial() -} - -/** - * Test harness using the Debug Test Module (DTM) to bringup the system - */ -class TestHarnessWithDTM(implicit p: Parameters) extends Module -{ - val io = IO(new Bundle { - val success = Output(Bool()) - }) - - // force Chisel to rename module - override def desiredName = "TestHarness" - - val dut = p(BuildTopWithDTM)(clock, reset.toBool, p) - - dut.reset := reset.asBool | dut.debug.get.ndreset dut.connectSimAXIMem() dut.connectSimAXIMMIO() dut.dontTouchPorts() @@ -84,5 +54,4 @@ class TestHarnessWithDTM(implicit p: Parameters) extends Module } }) - Debug.connectDebug(dut.debug, dut.psd, clock, reset.asBool, io.success) } diff --git a/generators/example/src/main/scala/Top.scala b/generators/example/src/main/scala/Top.scala index defb4ef4..cd222379 100644 --- a/generators/example/src/main/scala/Top.scala +++ b/generators/example/src/main/scala/Top.scala @@ -15,103 +15,33 @@ import utilities.{System, SystemModule} import sifive.blocks.devices.gpio._ import sifive.blocks.devices.uart._ -import icenet.{HasPeripheryIceNIC, HasPeripheryIceNICModuleImp} +import icenet.{CanHavePeripheryIceNIC, CanHavePeripheryIceNICModuleImp} // ------------------------------------ // BOOM and/or Rocket Top Level Systems // ------------------------------------ +// DOC include start: Top class Top(implicit p: Parameters) extends System - with HasNoDebug - with HasPeripherySerial - with CanHavePeripheryUARTWithAdapter { + with CanHavePeripheryUARTAdapter // Enables optionally adding the UART print adapter + with HasPeripheryUART // Enables optionally adding the sifive UART + with HasPeripheryGPIO // Enables optionally adding the sifive GPIOs + with CanHavePeripheryBlockDevice // Enables optionally adding the block device + with CanHavePeripheryInitZero // Enables optionally adding the initzero example widget + with CanHavePeripheryGCD // Enables optionally adding the GCD example widget + with CanHavePeripherySerial // Enables optionally adding the TSI serial-adapter and port + with CanHavePeripheryIceNIC // Enables optionally adding the IceNIC for firesim +{ override lazy val module = new TopModule(this) } class TopModule[+L <: Top](l: L) extends SystemModule(l) - with HasNoDebugModuleImp - with HasPeripherySerialModuleImp - with CanHavePeripheryUARTWithAdapterImp - with DontTouch - -//--------------------------------------------------------------------------------------------------------- -// DOC include start: TopWithPWMTL - -class TopWithPWMTL(implicit p: Parameters) extends Top - with HasPeripheryPWMTL { - override lazy val module = new TopWithPWMTLModule(this) -} - -class TopWithPWMTLModule(l: TopWithPWMTL) extends TopModule(l) - with HasPeripheryPWMTLModuleImp - -// DOC include end: TopWithPWMTL -//--------------------------------------------------------------------------------------------------------- - -class TopWithPWMAXI4(implicit p: Parameters) extends Top - with HasPeripheryPWMAXI4 { - override lazy val module = new TopWithPWMAXI4Module(this) -} - -class TopWithPWMAXI4Module(l: TopWithPWMAXI4) extends TopModule(l) - with HasPeripheryPWMAXI4ModuleImp - -//--------------------------------------------------------------------------------------------------------- - -class TopWithGCD(implicit p: Parameters) extends Top - with HasPeripheryGCD { - override lazy val module = new TopWithGCDModule(this) -} - -class TopWithGCDModule(l: TopWithGCD) extends TopModule(l) - with HasPeripheryGCDModuleImp - -//--------------------------------------------------------------------------------------------------------- - -class TopWithBlockDevice(implicit p: Parameters) extends Top - with HasPeripheryBlockDevice { - override lazy val module = new TopWithBlockDeviceModule(this) -} - -class TopWithBlockDeviceModule(l: TopWithBlockDevice) extends TopModule(l) - with HasPeripheryBlockDeviceModuleImp - -//--------------------------------------------------------------------------------------------------------- - -class TopWithGPIO(implicit p: Parameters) extends Top - with HasPeripheryGPIO { - override lazy val module = new TopWithGPIOModule(this) -} - -class TopWithGPIOModule(l: TopWithGPIO) - extends TopModule(l) with HasPeripheryGPIOModuleImp - -//--------------------------------------------------------------------------------------------------------- - -class TopWithDTM(implicit p: Parameters) extends System -{ - override lazy val module = new TopWithDTMModule(this) -} - -class TopWithDTMModule[+L <: TopWithDTM](l: L) extends SystemModule(l) - -//--------------------------------------------------------------------------------------------------------- -// DOC include start: TopWithInitZero -class TopWithInitZero(implicit p: Parameters) extends Top - with HasPeripheryInitZero { - override lazy val module = new TopWithInitZeroModuleImp(this) -} - -class TopWithInitZeroModuleImp(l: TopWithInitZero) extends TopModule(l) - with HasPeripheryInitZeroModuleImp -// DOC include end: TopWithInitZero - -class TopWithIceNIC(implicit p: Parameters) extends Top - with HasPeripheryIceNIC { - override lazy val module = new TopWithIceNICModule(this) -} - -class TopWithIceNICModule(outer: TopWithIceNIC) - extends TopModule(outer) - with HasPeripheryIceNICModuleImp + with HasPeripheryUARTModuleImp + with CanHavePeripheryBlockDeviceModuleImp + with CanHavePeripheryGCDModuleImp + with CanHavePeripherySerialModuleImp + with CanHavePeripheryIceNICModuleImp + with CanHavePeripheryUARTAdapterModuleImp + with DontTouch +// DOC include end: Top diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index c3a6ca80..f0c9c664 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -10,7 +10,7 @@ import freechips.rocketchip.devices.debug.HasPeripheryDebugModuleImp import freechips.rocketchip.subsystem.{CanHaveMasterAXI4MemPortModuleImp} import sifive.blocks.devices.uart.HasPeripheryUARTModuleImp -import testchipip.{HasPeripherySerialModuleImp, HasPeripheryBlockDeviceModuleImp} +import testchipip.{CanHavePeripherySerialModuleImp, CanHavePeripheryBlockDeviceModuleImp} import icenet.HasPeripheryIceNICModuleImpValidOnly import junctions.{NastiKey, NastiParameters} @@ -32,19 +32,19 @@ class WithTiedOffDebug extends RegisterBridgeBinder({ case target: HasPeripheryD }) class WithSerialBridge extends RegisterBridgeBinder({ - case target: HasPeripherySerialModuleImp => Seq(SerialBridge(target.serial)(target.p)) + case target: CanHavePeripherySerialModuleImp => Seq(SerialBridge(target.serial.get)(target.p)) }) class WithNICBridge extends RegisterBridgeBinder({ - case target: HasPeripheryIceNICModuleImpValidOnly => Seq(NICBridge(target.net)(target.p)) + case target: HasPeripheryIceNICModuleImpValidOnly => Seq(NICBridge(target.net)(target.p)) }) class WithUARTBridge extends RegisterBridgeBinder({ - case target: HasPeripheryUARTModuleImp => target.uart.map(u => UARTBridge(u)(target.p)) + case target: HasPeripheryUARTModuleImp => target.uart.map(u => UARTBridge(u)(target.p)) }) class WithBlockDeviceBridge extends RegisterBridgeBinder({ - case target: HasPeripheryBlockDeviceModuleImp => Seq(BlockDevBridge(target.bdev, target.reset.toBool)(target.p)) + case target: CanHavePeripheryBlockDeviceModuleImp => Seq(BlockDevBridge(target.bdev.get, target.reset.toBool)(target.p)) }) class WithFASEDBridge extends RegisterBridgeBinder({ diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 4cb0b990..17ac06e6 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -12,7 +12,7 @@ import freechips.rocketchip.subsystem._ import freechips.rocketchip.devices.tilelink.BootROMParams import freechips.rocketchip.devices.debug.{DebugModuleParams, DebugModuleKey} import boom.common.BoomTilesKey -import testchipip.{BlockDeviceKey, BlockDeviceConfig} +import testchipip.{BlockDeviceKey, BlockDeviceConfig, SerialKey} import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} import scala.math.{min, max} import tracegen.TraceGenKey @@ -47,13 +47,17 @@ class WithUARTKey extends Config((site, here, up) => { nRxEntries = 256)) }) +class WithSerial extends Config((site, here, up) => { + case SerialKey => true +}) + class WithBlockDevice extends Config(new testchipip.WithBlockDevice) class WithNICKey extends Config((site, here, up) => { - case NICKey => NICConfig( + case NICKey => Some(NICConfig( inBufFlits = 8192, ctrlQueueDepth = 64, - checksumOffload = true) + checksumOffload = true)) }) class WithRocketL2TLBs(entries: Int) extends Config((site, here, up) => { @@ -112,6 +116,7 @@ class FireSimRocketChipConfig extends Config( new WithoutTLMonitors ++ new WithUARTKey ++ new WithNICKey ++ + new WithSerial ++ new WithBlockDevice ++ new WithRocketL2TLBs(1024) ++ new WithPerfCounters ++ @@ -169,6 +174,7 @@ class FireSimBoomConfig extends Config( new WithoutTLMonitors ++ new WithUARTKey ++ new WithNICKey ++ + new WithSerial ++ new WithBlockDevice ++ new WithBoomL2TLBs(1024) ++ new WithoutClockGating ++ diff --git a/generators/firechip/src/main/scala/Targets.scala b/generators/firechip/src/main/scala/Targets.scala index 4c790195..b608e67b 100644 --- a/generators/firechip/src/main/scala/Targets.scala +++ b/generators/firechip/src/main/scala/Targets.scala @@ -42,10 +42,10 @@ class FireSimDUT(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology with CanHaveMasterAXI4MemPort with HasPeripheryBootROM - with HasPeripherySerial + with CanHavePeripherySerial with HasPeripheryUART - with HasPeripheryIceNIC - with HasPeripheryBlockDevice + with CanHavePeripheryIceNIC + with CanHavePeripheryBlockDevice with HasTraceIO { override lazy val module = new FireSimModuleImp(this) @@ -55,10 +55,10 @@ class FireSimModuleImp[+L <: FireSimDUT](l: L) extends SubsystemModuleImp(l) with HasRTCModuleImp with CanHaveMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp - with HasPeripherySerialModuleImp + with CanHavePeripherySerialModuleImp with HasPeripheryUARTModuleImp with HasPeripheryIceNICModuleImpValidOnly - with HasPeripheryBlockDeviceModuleImp + with CanHavePeripheryBlockDeviceModuleImp with HasTraceIOImp with CanHaveMultiCycleRegfileImp @@ -68,9 +68,9 @@ class FireSimNoNICDUT(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology with CanHaveMasterAXI4MemPort with HasPeripheryBootROM - with HasPeripherySerial + with CanHavePeripherySerial with HasPeripheryUART - with HasPeripheryBlockDevice + with CanHavePeripheryBlockDevice with HasTraceIO { override lazy val module = new FireSimNoNICModuleImp(this) @@ -80,9 +80,9 @@ class FireSimNoNICModuleImp[+L <: FireSimNoNICDUT](l: L) extends SubsystemModule with HasRTCModuleImp with CanHaveMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp - with HasPeripherySerialModuleImp + with CanHavePeripherySerialModuleImp with HasPeripheryUARTModuleImp - with HasPeripheryBlockDeviceModuleImp + with CanHavePeripheryBlockDeviceModuleImp with HasTraceIOImp with CanHaveMultiCycleRegfileImp @@ -107,12 +107,11 @@ class FireSimSupernode(implicit p: Parameters) extends DefaultFireSimHarness(() // Verilog blackbox integration demo class FireSimVerilogGCDDUT(implicit p: Parameters) extends FireSimDUT - with example.HasPeripheryGCD + with example.CanHavePeripheryGCD { override lazy val module = new FireSimVerilogGCDModuleImp(this) } class FireSimVerilogGCDModuleImp[+L <: FireSimVerilogGCDDUT](l: L) extends FireSimModuleImp(l) - with example.HasPeripheryGCDModuleImp class FireSimVerilogGCD(implicit p: Parameters) extends DefaultFireSimHarness(() => new FireSimVerilogGCDDUT) diff --git a/generators/icenet b/generators/icenet index 87b3bf5e..2874db7f 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit 87b3bf5e46da3db6f9a653fdd6786699c075bff3 +Subproject commit 2874db7fdc5bee81074bdfe9cbbd4f68a9881943 diff --git a/generators/sha3 b/generators/sha3 index 6814c999..faf08c0f 160000 --- a/generators/sha3 +++ b/generators/sha3 @@ -1 +1 @@ -Subproject commit 6814c9991336c5092e7ce7c06f7a8e8bc4283958 +Subproject commit faf08c0f39593b1005398830cc825bec43c0a610 diff --git a/generators/testchipip b/generators/testchipip index db01ac15..62cf2629 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit db01ac1514d68fe55af2eb8f5bffb52da596ed75 +Subproject commit 62cf2629a7f2df054224c7dfbb9ff84b9e2b1203 diff --git a/sims/firesim b/sims/firesim index d799550b..5f6bd4fa 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit d799550b42c4bf0a1030cf93dde3a27263bfcc95 +Subproject commit 5f6bd4fa16af5d2fc15c49b54358f57dbd2c1469 From f0c441b7e1e4442131abe616cd99d24e55d9c480 Mon Sep 17 00:00:00 2001 From: John Wright Date: Tue, 21 Jan 2020 21:01:09 -0800 Subject: [PATCH 43/75] [skip ci] Fix the logo in README.md (#389) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79a6b533..2ef59584 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![CHIPYARD](https://github.com/ucb-bar/chipyard/raw/alon-docs-dev/docs/_static/images/chipyard-logo-full.png) +![CHIPYARD](https://github.com/ucb-bar/chipyard/raw/master/docs/_static/images/chipyard-logo-full.png) # Chipyard Framework [![CircleCI](https://circleci.com/gh/ucb-bar/chipyard/tree/master.svg?style=svg)](https://circleci.com/gh/ucb-bar/chipyard/tree/master) From 335bbf765115c2833ba31bb03160d229b439e215 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Wed, 22 Jan 2020 09:08:05 -0800 Subject: [PATCH 44/75] Patch parallel make (#386) * fix parallel make non-deterministic issue * change touch to echo to not affect file state --- common.mk | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/common.mk b/common.mk index 8581fbb0..98ee2bb1 100644 --- a/common.mk +++ b/common.mk @@ -40,10 +40,12 @@ $(sim_files): $(call lookup_scala_srcs,$(base_dir)/generators/utilities/src/main ######################################################################################### .INTERMEDIATE: generator_temp $(FIRRTL_FILE) $(ANNO_FILE): generator_temp + @echo "" > /dev/null + generator_temp: $(SCALA_SOURCES) $(sim_files) mkdir -p $(build_dir) cd $(base_dir) && $(SBT) "project $(SBT_PROJECT)" "runMain $(GENERATOR_PACKAGE).Generator $(build_dir) $(MODEL_PACKAGE) $(MODEL) $(CONFIG_PACKAGE) $(CONFIG)" - + .PHONY: firrtl firrtl: $(FIRRTL_FILE) @@ -57,8 +59,11 @@ TOP_TARGETS = $(TOP_FILE) $(TOP_SMEMS_CONF) $(TOP_ANNO) $(TOP_FIR) $(sim_top_bla HARNESS_TARGETS = $(HARNESS_FILE) $(HARNESS_SMEMS_CONF) $(HARNESS_ANNO) $(HARNESS_FIR) $(sim_harness_blackboxes) # DOC include start: FirrtlCompiler +# NOTE: These *_temp intermediate targets will get removed in favor of make 4.3 grouped targets (&: operator) .INTERMEDIATE: firrtl_temp $(TOP_TARGETS) $(HARNESS_TARGETS): firrtl_temp + @echo "" > /dev/null + firrtl_temp: $(FIRRTL_FILE) $(ANNO_FILE) cd $(base_dir) && $(SBT) "project tapeout" "runMain barstools.tapeout.transforms.GenerateTopAndHarness -o $(TOP_FILE) -tho $(HARNESS_FILE) -i $(FIRRTL_FILE) --syn-top $(TOP) --harness-top $(VLOG_MODEL) -faf $(ANNO_FILE) -tsaof $(TOP_ANNO) -tdf $(sim_top_blackboxes) -tsf $(TOP_FIR) -thaof $(HARNESS_ANNO) -hdf $(sim_harness_blackboxes) -thf $(HARNESS_FIR) $(REPL_SEQ_MEM) $(HARNESS_CONF_FLAGS) -td $(build_dir)" && touch $(sim_top_blackboxes) $(sim_harness_blackboxes) # DOC include end: FirrtlCompiler @@ -67,12 +72,16 @@ firrtl_temp: $(FIRRTL_FILE) $(ANNO_FILE) MACROCOMPILER_MODE ?= --mode synflops .INTERMEDIATE: top_macro_temp $(TOP_SMEMS_FILE) $(TOP_SMEMS_FIR): top_macro_temp + @echo "" > /dev/null + top_macro_temp: $(TOP_SMEMS_CONF) cd $(base_dir) && $(SBT) "project barstoolsMacros" "runMain barstools.macros.MacroCompiler -n $(TOP_SMEMS_CONF) -v $(TOP_SMEMS_FILE) -f $(TOP_SMEMS_FIR) $(MACROCOMPILER_MODE)" HARNESS_MACROCOMPILER_MODE = --mode synflops .INTERMEDIATE: harness_macro_temp $(HARNESS_SMEMS_FILE) $(HARNESS_SMEMS_FIR): harness_macro_temp + @echo "" > /dev/null + harness_macro_temp: $(HARNESS_SMEMS_CONF) cd $(base_dir) && $(SBT) "project barstoolsMacros" "runMain barstools.macros.MacroCompiler -n $(HARNESS_SMEMS_CONF) -v $(HARNESS_SMEMS_FILE) -f $(HARNESS_SMEMS_FIR) $(HARNESS_MACROCOMPILER_MODE)" From 5358d2952bf8fb22b18309e8a028ff08d95b4ca2 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Wed, 22 Jan 2020 09:08:38 -0800 Subject: [PATCH 45/75] add scratchpad config (default size = 4MB) | other misc comments (#383) --- .../example/src/main/scala/ConfigMixins.scala | 43 ++++++++++++++++++- .../src/main/scala/RocketConfigs.scala | 17 +++++++- generators/example/src/main/scala/Top.scala | 3 +- .../example/src/main/scala/TopCakes.scala | 27 ++++++++++++ 4 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 generators/example/src/main/scala/TopCakes.scala diff --git a/generators/example/src/main/scala/ConfigMixins.scala b/generators/example/src/main/scala/ConfigMixins.scala index b3deeb3f..acd1001e 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -35,12 +35,18 @@ import ConfigValName._ // Common Parameter Mixins // ----------------------- +/** + * Mixin to add the Chipyard bootrom + */ class WithBootROM extends Config((site, here, up) => { case BootROMParams => BootROMParams( contentFileName = s"./bootrom/bootrom.rv${site(XLen)}.img") }) // DOC include start: gpio mixin +/** + * Mixin to add GPIOs and tie them off outside the DUT + */ class WithGPIO extends Config((site, here, up) => { case PeripheryGPIOKey => Seq( GPIOParams(address = 0x10012000, width = 4, includeIOF = false)) @@ -61,19 +67,24 @@ class WithGPIO extends Config((site, here, up) => { // DOC include end: gpio mixin /** - * Class to add in UART + * Mixin to add in UART */ class WithUART extends Config((site, here, up) => { case PeripheryUARTKey => Seq( UARTParams(address = 0x54000000L, nTxEntries = 256, nRxEntries = 256)) }) - +/** + * Mixin to remove any GPIOs + */ class WithNoGPIO extends Config((site, here, up) => { case PeripheryGPIOKey => Seq() }) // DOC include start: tsi mixin +/** + * Mixin to add an offchip TSI link (used for backing memory) + */ class WithTSI extends Config((site, here, up) => { case SerialKey => true case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { @@ -84,6 +95,9 @@ class WithTSI extends Config((site, here, up) => { }) // DOC include end: tsi mixin +/** + * Mixin to add an DTM (used for dmi or jtag bringup) + */ class WithDTM extends Config((site, here, up) => { case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { val top = up(BuildTop, site)(clock, reset, p, success) @@ -94,11 +108,17 @@ class WithDTM extends Config((site, here, up) => { }) // DOC include start: GCD mixin +/** + * Mixin to add a GCD peripheral + */ class WithGCD(useAXI4: Boolean, useBlackBox: Boolean) extends Config((site, here, up) => { case GCDKey => Some(GCDParams(useAXI4 = useAXI4, useBlackBox = useBlackBox)) }) // DOC include end: GCD mixin +/** + * Mixin to add a RTL block device model + */ class WithBlockDeviceModel extends Config((site, here, up) => { case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { val top = up(BuildTop, site)(clock, reset, p, success) @@ -107,6 +127,9 @@ class WithBlockDeviceModel extends Config((site, here, up) => { } }) +/** + * Mixin to add a simulated block device model + */ class WithSimBlockDevice extends Config((site, here, up) => { case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { val top = up(BuildTop, site)(clock, reset, p, success) @@ -116,6 +139,9 @@ class WithSimBlockDevice extends Config((site, here, up) => { }) // DOC include start: WithInitZero +/** + * Mixin to add a peripheral that clears memory + */ class WithInitZero(base: BigInt, size: BigInt) extends Config((site, here, up) => { case InitZeroKey => Some(InitZeroConfig(base, size)) }) @@ -190,6 +216,9 @@ class WithControlCore extends Config((site, here, up) => { case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) }) +/** + * Mixin to add an IceNIC + */ class WithIceNIC(inBufFlits: Int = 1800, usePauser: Boolean = false) extends Config((site, here, up) => { case NICKey => Some(NICConfig( @@ -198,6 +227,9 @@ class WithIceNIC(inBufFlits: Int = 1800, usePauser: Boolean = false) checksumOffload = true)) }) +/** + * Mixin to loopback the IceNIC + */ class WithLoopbackNIC extends Config((site, here, up) => { case BuildTop => (clock: Clock, reset: Bool, p: Parameters, success: Bool) => { val top = up(BuildTop, site)(clock, reset, p, success) @@ -205,3 +237,10 @@ class WithLoopbackNIC extends Config((site, here, up) => { top } }) + +/** + * Mixin to add a backing scratchpad (default size 4MB) + */ +class WithBackingScratchpad(base: BigInt = 0x80000000L, mask: BigInt = ((4 << 20) - 1)) extends Config((site, here, up) => { + case BackingScratchpadKey => Some(BackingScratchpadParams(base, mask)) +}) diff --git a/generators/example/src/main/scala/RocketConfigs.scala b/generators/example/src/main/scala/RocketConfigs.scala index 4ccc2fd4..7cc43a4d 100644 --- a/generators/example/src/main/scala/RocketConfigs.scala +++ b/generators/example/src/main/scala/RocketConfigs.scala @@ -216,9 +216,9 @@ class InitZeroRocketConfig extends Config( class LoopbackNICRocketConfig extends Config( new WithTSI ++ - new WithIceNIC ++ + new WithIceNIC ++ // add an IceNIC new WithNoGPIO ++ - new WithLoopbackNIC ++ + new WithLoopbackNIC ++ // loopback the IceNIC new WithBootROM ++ new WithUART ++ new freechips.rocketchip.subsystem.WithNoMMIOPort ++ @@ -226,3 +226,16 @@ class LoopbackNICRocketConfig extends Config( new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) + +class ScratchpadRocketConfig extends Config( + new WithTSI ++ + new WithNoGPIO ++ + new WithBootROM ++ + new WithUART ++ + new WithBackingScratchpad ++ // add backing scratchpad + new freechips.rocketchip.subsystem.WithNoMemPort ++ // remove offchip mem port + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) diff --git a/generators/example/src/main/scala/Top.scala b/generators/example/src/main/scala/Top.scala index cd222379..47ab1c28 100644 --- a/generators/example/src/main/scala/Top.scala +++ b/generators/example/src/main/scala/Top.scala @@ -30,7 +30,8 @@ class Top(implicit p: Parameters) extends System with CanHavePeripheryInitZero // Enables optionally adding the initzero example widget with CanHavePeripheryGCD // Enables optionally adding the GCD example widget with CanHavePeripherySerial // Enables optionally adding the TSI serial-adapter and port - with CanHavePeripheryIceNIC // Enables optionally adding the IceNIC for firesim + with CanHavePeripheryIceNIC // Enables optionally adding the IceNIC for FireSim + with CanHaveBackingScratchpad // Enables optionally adding a backing scratchpad { override lazy val module = new TopModule(this) } diff --git a/generators/example/src/main/scala/TopCakes.scala b/generators/example/src/main/scala/TopCakes.scala new file mode 100644 index 00000000..30f13e48 --- /dev/null +++ b/generators/example/src/main/scala/TopCakes.scala @@ -0,0 +1,27 @@ +package example + +import chisel3._ + +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.config.{Field} +import freechips.rocketchip.diplomacy.{LazyModule, AddressSet} +import freechips.rocketchip.tilelink.{TLRAM} + +case class BackingScratchpadParams( + base: BigInt, + mask: BigInt) + +case object BackingScratchpadKey extends Field[Option[BackingScratchpadParams]](None) + +/** + * Trait to add a scratchpad on the mbus + */ +trait CanHaveBackingScratchpad { this: BaseSubsystem => + private val portName = "Backing-Scratchpad" + + val spadOpt = p(BackingScratchpadKey).map { param => + val spad = LazyModule(new TLRAM(address=AddressSet(param.base, param.mask), beatBytes=mbus.beatBytes)) + mbus.toVariableWidthSlave(Some(portName)) { spad.node } + spad + } +} From cb2f48b148b13f9372fff42b6ba1d09d067633e1 Mon Sep 17 00:00:00 2001 From: alonamid Date: Wed, 22 Jan 2020 13:40:59 -0800 Subject: [PATCH 46/75] System Requirements (#387) * more system requirements * [ci skip] system reqs PR comments * scripts: Make {ubuntu,centos}-req.sh executable [ci skip] * scripts: Add Ubuntu toolchain dependencies [ci skip] * inline marshal reqs * [skip ci] Update scripts/centos-req.sh Co-Authored-By: Albert Ou Co-authored-by: Albert Ou --- docs/Chipyard-Basics/Initial-Repo-Setup.rst | 13 +++++++++++++ scripts/centos-req.sh | 18 ++++++++++++++++++ scripts/ubuntu-req.sh | 19 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100755 scripts/centos-req.sh create mode 100755 scripts/ubuntu-req.sh diff --git a/docs/Chipyard-Basics/Initial-Repo-Setup.rst b/docs/Chipyard-Basics/Initial-Repo-Setup.rst index 1ab06c7a..931da013 100644 --- a/docs/Chipyard-Basics/Initial-Repo-Setup.rst +++ b/docs/Chipyard-Basics/Initial-Repo-Setup.rst @@ -10,6 +10,19 @@ Chipyard is developed and tested on Linux-based systems. .. Warning:: Working under Windows is not recommended. + +In CentOS-based platforms, we recommend installing the following dependencies: + +.. include:: /../scripts/centos-req.sh + :code: bash + +In Ubuntu/Debian-based platforms (Ubuntu), we recommend installing the following dependencies: + +.. include:: /../scripts/ubuntu-req.sh + :code: bash + +.. Note:: When running on an Amazon Web Services EC2 FPGA-development instance (for FireSim), FireSim includes a machine setup script that will install all of the aforementioned dependencies (and some additional ones). + Checking out the sources ------------------------ diff --git a/scripts/centos-req.sh b/scripts/centos-req.sh new file mode 100755 index 00000000..8fac61af --- /dev/null +++ b/scripts/centos-req.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +sudo yum groupinstall -y "Development tools" +sudo yum install -y gmp-devel mpfr-devel libmpc-devel zlib-devel vim git java java-devel +curl https://bintray.com/sbt/rpm/rpm | sudo tee /etc/yum.repos.d/bintray-sbt-rpm.repo +sudo yum install -y sbt texinfo gengetopt +sudo yum install -y expat-devel libusb1-devel ncurses-devel cmake "perl(ExtUtils::MakeMaker)" +# deps for poky +sudo yum install -y python36 patch diffstat texi2html texinfo subversion chrpath git wget +# deps for qemu +sudo yum install -y gtk3-devel +# deps for firemarshal +sudo yum install -y python36-pip python36-devel rsync libguestfs-tools makeinfo expat ctags +# Install GNU make 4.x (needed to cross-compile glibc 2.28+) +sudo yum install -y centos-release-scl +sudo yum install -y devtoolset-8-make +# install DTC +sudo yum install -y dtc diff --git a/scripts/ubuntu-req.sh b/scripts/ubuntu-req.sh new file mode 100755 index 00000000..1858c3a4 --- /dev/null +++ b/scripts/ubuntu-req.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +sudo apt-get install -y build-essential bison flex +sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev zlib1g-dev vim git default-jdk default-jre +# install sbt: https://www.scala-sbt.org/release/docs/Installing-sbt-on-Linux.html +echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list +curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add +sudo apt-get update +sudo apt-get install -y sbt +sudo apt-get install -y texinfo gengetopt +sudo apt-get install -y libxpat1-dev libusb-dev libncurses5-dev cmake +# deps for poky +sudo apt-get install -y python3.6 patch diffstat texi2html texinfo subversion chrpath git wget +# deps for qemu +sudo apt-get install -y libgtk-3-dev +# deps for firemarshal +sudo apt-get install -y python3-pip python3.6-dev rsync libguestfs-tools expat ctags +# install DTC +sudo apt-get install -y device-tree-compiler From 44883b238b00f73e539bf5bada010899f0905162 Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Wed, 22 Jan 2020 14:09:50 -0800 Subject: [PATCH 47/75] [sbt] Don't rely on target-rtl symlink when FireSim is top (#328) From 1859054f73a91d53c9301bd8a2976b8d888b7056 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 23 Jan 2020 13:36:21 -0800 Subject: [PATCH 48/75] [docs] update documentation [ci skip] (#393) --- docs/Advanced-Concepts/Chip-Communication.rst | 29 +++-- docs/Advanced-Concepts/Debugging-RTL.rst | 13 ++- docs/Advanced-Concepts/Top-Testharness.rst | 31 +----- docs/Customization/Boot-Process.rst | 2 +- docs/Customization/Heterogeneous-SoCs.rst | 8 +- .../Incorporating-Verilog-Blocks.rst | 8 +- docs/Customization/Keys-Traits-Configs.rst | 4 +- docs/Customization/MMIO-Peripherals.rst | 2 +- docs/Customization/Memory-Hierarchy.rst | 102 ++++++++++++------ docs/Customization/index.rst | 2 +- docs/VLSI/Advanced-Usage.rst | 6 +- docs/_static/images/chip-bringup.png | Bin 18259 -> 18536 bytes 12 files changed, 117 insertions(+), 90 deletions(-) diff --git a/docs/Advanced-Concepts/Chip-Communication.rst b/docs/Advanced-Concepts/Chip-Communication.rst index 92efd17c..29979900 100644 --- a/docs/Advanced-Concepts/Chip-Communication.rst +++ b/docs/Advanced-Concepts/Chip-Communication.rst @@ -48,8 +48,8 @@ By default, Chipyard uses the Tethered Serial Interface (TSI) to communicate wit 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 probe the DUT's memory space. During simulation, the host sends TSI commands to a -simulation stub called ``SimSerial`` (C++ class) that resides in a ``SimSerial`` verilog module -(both are located in the ``generators/testchipip`` project). This ``SimSerial`` verilog module then +simulation stub called ``SimSerial`` (C++ class) that resides in a ``SimSerial`` Verilog module +(both are located in the ``generators/testchipip`` project). This ``SimSerial`` Verilog module then sends the TSI command recieved by the simulation stub into the DUT which then converts the TSI command into a TileLink request. This conversion is done by the ``SerialAdapter`` module (located in the ``generators/testchipip`` project). In simulation, FESVR @@ -60,11 +60,19 @@ mechanism to communicate with the DUT in simulation. In the case of a chip tapeout bringup, TSI commands can be sent over a custom communication medium to communicate with the chip. For example, some Berkeley tapeouts have a FPGA with a RISC-V soft-core that runs FESVR. The FESVR on the soft-core sends TSI commands -to a TSI-to-TileLink converter living on the FPGA (i.e. ``SerialAdapter``). Then this converter -sends the converted TileLink commands over a serial link to the chip. The following image shows this flow: +to a TSI-to-TileLink converter living on the FPGA (i.e. ``SerialAdapter``). 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 +serial-link or serdes). Once the serialized transaction is received on the +chip, it is deserialized and masters a bus on the chip. The following image shows this flow: .. image:: ../_static/images/chip-bringup.png +.. note:: + The ``TLSerdesser`` can also be used as a slave (client), so it can sink memory requests from the chip + and connect to off-chip backing memory. Or in other words, ``TLSerdesser`` creates a bi-directional TileLink + interface. + Using the Debug Module Interface (DMI) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -75,8 +83,8 @@ The DTM is given in the `RISC-V Debug Specification `__ .website. In addition, developers -may insert arbitrary printfs at arbitrary conditions within the Chisel g -enerators. See the Chisel documentation for information on this. +For information see the Rocket core source code, or the BOOM `documentation +`__ website. In addition, developers +may insert arbitrary printfs at arbitrary conditions within the Chisel generators. +See the Chisel documentation for information on this. Once the cores have been configured with the desired print statements, the ``+verbose`` flag will cause the simulator to print the statements. The following @@ -56,6 +60,7 @@ commands will all generate desired print statements: .. code-block:: shell make CONFIG=CustomConfig run-binary-debug BINARY=helloworld.riscv + # The below command does the same thing ./simv-CustomConfig-debug +verbose helloworld.riscv diff --git a/docs/Advanced-Concepts/Top-Testharness.rst b/docs/Advanced-Concepts/Top-Testharness.rst index 1256ea59..3d22e54a 100644 --- a/docs/Advanced-Concepts/Top-Testharness.rst +++ b/docs/Advanced-Concepts/Top-Testharness.rst @@ -4,7 +4,7 @@ Tops, Test-Harnesses, and the Test-Driver The three highest levels of hierarchy in a Chipyard SoC are the Top (DUT), ``TestHarness``, and the ``TestDriver``. The Top and ``TestHarness`` are both emitted by Chisel generators. -The ``TestDriver`` serves as our testbench, and is a verilog +The ``TestDriver`` serves as our testbench, and is a Verilog file in Rocket Chip. @@ -45,22 +45,13 @@ System Tops ^^^^^^^^^^^^^^^^^^^^^^^^^ -A SoC Top then extends the ``System`` class with any config-specific components. There are two "classes" of Tops in Chipyard that enable different bringup methods. +A SoC Top then extends the ``System`` class with any config-specific components. +In Chipyard, this includes things like adding a NIC, UART, and GPIO as well as setting up the hardware for the bringup method. Please refer to :ref:`Communicating with the DUT` for more information on these bringup methods. -- ``Top`` is the default setup. These top modules instantiate a serial module which interfaces with the ``TestHarness``. In addition, the Debug Transfer Module (DTM) is removed and replaced with a TSI-based bringup flow. All other example "Tops" (except the ``TopWithDTM``) extend this Top as the "base" top-level system. -- ``TopWithDTM`` does not include the TSI-based bringup flow. Instead it keeps the Debug Transfer Module (DTM) within the design so that you can use a DMI-based or JTAG-based bringup. - -For a custom Top a mixed-in trait adds the additional modules or IOs (an example of this is ``TopWithGPIO``). - TestHarness ------------------------- -There are two variants of ``TestHarness`` generators in Chipyard, both located in -`generators/example/src/main/scala/TestHarness.scala `__. -One is designed for TSI-based bringup, while the other performs DTM-based bringup. -See :ref:`Communicating with the DUT` for more information on these two methodologies. - The wiring between the ``TestHarness`` and the Top are performed in methods defined in mixins added to the Top. When these methods are called from the ``TestHarness``, they may instantiate modules within the scope of the harness, and then connect them to the DUT. For example, the ``connectSimAXIMem`` method defined in the @@ -70,21 +61,9 @@ and connect them to the correct IOs of the top. While this roundabout way of attaching to the IOs of the top may seem to be unnecessarily complex, it allows the designer to compose custom traits together without having to worry about the details of the implementation of any particular trait. -Specifying a Top -^^^^^^^^^^^^^^^^^^^^^^^^^ - -To see why the Top connection method is useful, consider the case where we want to use a custom Top with additional GPIO pins. -In `generators/example/src/main/scala/Top.scala `__, -we can see how the ``TopWithGPIO`` class adds the ``HasPeripheryGPIO`` trait. This trait adds IOs to the Top module, -instantiates a TileLink GPIO node, and connects it to the proper buses. - -If we look at the ``WithGPIOTop`` mixin in the ``ConfigMixins.scala`` file, we see that adding this mixin to the top-level Config overrides the -``BuildTop`` key with a custom function that both instantiates the custom Top, and drives all the GPIO pins. -When the ``TestHarness`` looks up the ``BuildTop`` key, this function will run and perform the specified wiring, and then return the Top module. - TestDriver ------------------------- The ``TestDriver`` is defined in ``generators/rocketchip/src/main/resources/vsrc/TestDriver.v``. -This verilog file executes a simulation by instantiating the ``TestHarness``, driving the clock and reset signals, and interpreting the success output. -This file is compiled with the generated verilog for the ``TestHarness`` and the Top to produce a simulator. +This Verilog file executes a simulation by instantiating the ``TestHarness``, driving the clock and reset signals, and interpreting the success output. +This file is compiled with the generated Verilog for the ``TestHarness`` and the Top to produce a simulator. diff --git a/docs/Customization/Boot-Process.rst b/docs/Customization/Boot-Process.rst index d23fae85..b6b5e8a3 100644 --- a/docs/Customization/Boot-Process.rst +++ b/docs/Customization/Boot-Process.rst @@ -17,7 +17,7 @@ The BootROM address space starts at ``0x10000`` (determined by the ``BootROMPara The Chisel generator encodes the assembled instructions into the BootROM hardware at elaboration time, so if you want to change the BootROM code, you will need to run ``make`` in the bootrom directory and then regenerate the -verilog. If you don't want to overwrite the existing ``bootrom.S``, you can +Verilog. If you don't want to overwrite the existing ``bootrom.S``, you can also point the generator to a different bootrom image by overriding the ``BootROMParams`` key in the configuration. diff --git a/docs/Customization/Heterogeneous-SoCs.rst b/docs/Customization/Heterogeneous-SoCs.rst index 116d4ae9..e1d58c6a 100644 --- a/docs/Customization/Heterogeneous-SoCs.rst +++ b/docs/Customization/Heterogeneous-SoCs.rst @@ -19,7 +19,7 @@ The following example shows a dual core BOOM with a single core Rocket. :end-before: DOC include end: DualBoomAndRocket In this example, the ``WithNBoomCores`` and ``WithNBigCores`` mixins set up the default parameters for the multiple BOOM and Rocket cores, respectively. -However, for BOOM, an extra mixin called ``LargeBoomConfig`` is added to override the default parameters with a different set of more common default parameters. +However, for BOOM, an extra mixin called ``WithLargeBooms`` is added to override the default parameters with a different set of more common default parameters. This mixin applies to all BOOM cores in the system and changes the parameters for each. Great! Now you have a heterogeneous setup with BOOMs and Rockets. @@ -55,8 +55,12 @@ Then you could use this new mixin like the following. .. code-block:: scala class SixCoreConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ + new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ new WithHeterCoresSetup ++ new freechips.rocketchip.system.BaseConfig) diff --git a/docs/Customization/Incorporating-Verilog-Blocks.rst b/docs/Customization/Incorporating-Verilog-Blocks.rst index 48f0c6e3..fc1b8d7d 100644 --- a/docs/Customization/Incorporating-Verilog-Blocks.rst +++ b/docs/Customization/Incorporating-Verilog-Blocks.rst @@ -61,7 +61,7 @@ and Verilog sources follow the prescribed directory layout. resources/ vsrc/ GCDMMIOBlackBox.v - + Defining a Chisel BlackBox -------------------------- @@ -78,11 +78,11 @@ Of particular interest is the fact that parameterized Verilog modules can be passed the full space of possible parameter values. These values may depend on elaboration-time values in the Chisel generator, as the bitwidth of the GCD calculation does in this example. - + **Verilog GCD port list and parameters** .. literalinclude:: ../../generators/example/src/main/resources/vsrc/GCDMMIOBlackBox.v - :language: verilog + :language: Verilog :start-after: DOC include start: GCD portlist :end-before: DOC include end: GCD portlist @@ -113,7 +113,7 @@ Defining a Chip with a BlackBox --------------------------------------- Since we've parameterized the GCD instantiation to choose between the -Chisel and the verilog module, creating a config is easy. +Chisel and the Verilog module, creating a config is easy. .. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala :language: scala diff --git a/docs/Customization/Keys-Traits-Configs.rst b/docs/Customization/Keys-Traits-Configs.rst index 8184975f..e7705f44 100644 --- a/docs/Customization/Keys-Traits-Configs.rst +++ b/docs/Customization/Keys-Traits-Configs.rst @@ -21,7 +21,7 @@ Keys should be defined and documented in sub-projects, since they generally deal :start-after: DOC include start: GCD key :end-before: DOC include end: GCD key -The object within a key is typically a ``case class XXXParams``, which defines a set of parameters which some block accepts. For example, the GCD widget's ``GCDParams`` parameterizes its address, operand widths, whether the widget should be connected by Tilelink or AXI4, and whether the widget should use the blackbox-verilog implementation, or the Chisel implementation. +The object within a key is typically a ``case class XXXParams``, which defines a set of parameters which some block accepts. For example, the GCD widget's ``GCDParams`` parameterizes its address, operand widths, whether the widget should be connected by Tilelink or AXI4, and whether the widget should use the blackbox-Verilog implementation, or the Chisel implementation. .. literalinclude:: ../../generators/example/src/main/scala/GCD.scala @@ -95,7 +95,7 @@ For example, conside a config that contains the mixins ``WithGPIO ++ WithTSI``. When ``WithGPIO ++ WithTSI`` is evaluated right to left, the call to ``up(BuildTop, site)`` in ``WithGPIO`` will reference the function defined in the ``BuildTop`` key of ``WithTSI``. Thus, at elaboration time, when the ``BuildTop`` function is called by the ``TestHarness``, first the ``BuildTop`` function in ``WithTSI`` will be evaluated. This connects the ``success`` signal of the ``TestHarness`` to the ``SerialAdapter`` enabled by ``WithTSI``. Then, the rest of the code in the ``BuildTop`` function of ``WithGPIO`` will execute, tieing off the top-level GPIO input pins. Thus the evaluation of the ``BuildTop`` functions in a completed config is "right-to-left", matching how the evaluation of the mixins at compile-time is also "right-to-left". .. warning:: - Note that in some cases, the ordering and duplication of mixins which extend ``BuildTop`` will have unintended consequences. + In some cases, the ordering and duplication of mixins which extend ``BuildTop`` will have unintended consequences. For example, ``WithTSI ++ WithTSI`` will attempt to generate and connect two ``SimSerial`` widgets in the ``TestHarness``, which will likely break the simulation. In general, you should avoid attaching multiple mixins which interface to the same top-level ports. diff --git a/docs/Customization/MMIO-Peripherals.rst b/docs/Customization/MMIO-Peripherals.rst index 0e01edb5..23fddca4 100644 --- a/docs/Customization/MMIO-Peripherals.rst +++ b/docs/Customization/MMIO-Peripherals.rst @@ -127,7 +127,7 @@ Now we can test that the GCD is working. The test program is in ``tests/gcd.c``. This just writes out to the registers we defined earlier. The base of the module's MMIO region is at 0x2000 by default. -This will be printed out in the address map portion when you generate the verilog code. +This will be printed out in the address map portion when you generate the Verilog code. You can also see how this changes the emitted ``.json`` addressmap files in ``generated-src``. Compiling this program with ``make`` produces a ``gcd.riscv`` executable. diff --git a/docs/Customization/Memory-Hierarchy.rst b/docs/Customization/Memory-Hierarchy.rst index 65724483..6266e435 100644 --- a/docs/Customization/Memory-Hierarchy.rst +++ b/docs/Customization/Memory-Hierarchy.rst @@ -15,18 +15,24 @@ configure 4 KiB direct-mapped caches for L1I and L1D. .. code-block:: scala class SmallRocketConfig extends Config( - new WithTop ++ // use default top - new WithBootROM ++ // use default bootrom - new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ + new WithTSI ++ + new WithNoGPIO ++ + new WithBootROM ++ + new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ + new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ // small rocket cores new freechips.rocketchip.system.BaseConfig) - class SmallRocketConfig extends Config( - new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ - new RocketConfig) - class MediumRocketConfig extends Config( - new freechips.rocketchip.subsystem.WithNMedCores(1) ++ - new RocketConfig) + new WithTSI ++ + new WithNoGPIO ++ + new WithBootROM ++ + new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ + new freechips.rocketchip.subsystem.WithNMedCores(1) ++ // medium rocket cores + new freechips.rocketchip.system.BaseConfig) If you only want to change the size or associativity, there are configuration mixins for those too. @@ -36,11 +42,18 @@ mixins for those too. import freechips.rocketchip.subsystem.{WithL1ICacheSets, WithL1DCacheSets, WithL1ICacheWays, WithL1DCacheWays} class MyL1RocketConfig extends Config( - new WithL1ICacheSets(128) ++ - new WithL1ICacheWays(2) ++ - new WithL1DCacheSets(128) ++ - new WithL1DCacheWays(2) ++ - new RocketConfig) + new WithTSI ++ + new WithNoGPIO ++ + new WithBootROM ++ + new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ + new WithL1ICacheSets(128) ++ // change rocket I$ + new WithL1ICacheWays(2) ++ // change rocket I$ + new WithL1DCacheSets(128) ++ // change rocket D$ + new WithL1DCacheWays(2) ++ // change rocket D$ + new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ + new freechips.rocketchip.system.BaseConfig) You can also configure the L1 data cache as an data scratchpad instead. However, there are some limitations on this. If you are using a data scratchpad, @@ -49,18 +62,22 @@ Note that these configurations fully remove the L2 cache and mbus. .. code-block:: scala - class SmallRocketConfigNoL2 extends Config( - new WithTop ++ // use default top - new WithBootROM ++ // use default bootrom - new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ - new freechips.rocketchip.system.BaseConfig) - + class SmallRocketConfigNoL2 extends Config( + new WithTSI ++ + new WithNoGPIO ++ + new WithBootROM ++ + new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ + new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ + new freechips.rocketchip.system.BaseConfig) + class ScratchpadRocketConfig extends Config( - new freechips.rocketchip.subsystem.WithNoMemPort ++ - new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ - new freechips.rocketchip.subsystem.WithNBanks(0) ++ - new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ - new SmallRocketConfigNoL2) + new freechips.rocketchip.subsystem.WithNoMemPort ++ + new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ + new freechips.rocketchip.subsystem.WithNBanks(0) ++ + new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ + new SmallRocketConfigNoL2) This configuration fully removes the L2 cache and memory bus by setting the number of channels and number of banks to 0. @@ -79,13 +96,19 @@ and the number of banks must be powers of 2. import freechips.rocketchip.subsystem.WithInclusiveCache - # Create an SoC with 1 MB, 4-way, 4-bank cache class MyCacheRocketConfig extends Config( - new WithInclusiveCache( + new WithTSI ++ + new WithNoGPIO ++ + new WithBootROM ++ + new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ + new WithInclusiveCache( // add 1MB, 4-way, 4-bank cache capacityKB = 1024, nWays = 4, nBanks = 4) ++ - new RocketConfig) + new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ + new freechips.rocketchip.system.BaseConfig) The Broadcast Hub ----------------- @@ -99,13 +122,15 @@ list of included mixims. .. code-block:: scala - import freechips.rocketchip.subsystem.{WithNBigCores, BaseConfig} - class CachelessRocketConfig extends Config( - new WithTop ++ + new WithTSI ++ + new WithNoGPIO ++ new WithBootROM ++ - new WithNBigCores(1) ++ - new BaseConfig) + new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) If you want to reduce the resources used even further, you can configure the Broadcast Hub to use a bufferless design. @@ -133,8 +158,15 @@ number of DRAM channels is restricted to powers of two. import freechips.rocketchip.subsystem.WithNMemoryChannels class DualChannelRocketConfig extends Config( - new WithNMemoryChannels(2) ++ - new RocketConfig) + new WithTSI ++ + new WithNoGPIO ++ + new WithBootROM ++ + new WithUART ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ + new WithNMemoryChannels(2) ++ // multi-channel outer mem + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) In VCS and Verilator simulation, the DRAM is simulated using the ``SimAXIMem`` module, which simply attaches a single-cycle SRAM to each diff --git a/docs/Customization/index.rst b/docs/Customization/index.rst index c76c1f3f..c5ec5778 100644 --- a/docs/Customization/index.rst +++ b/docs/Customization/index.rst @@ -17,7 +17,7 @@ These guides will walk you through customization of your system-on-chip: - Connect widgets which act as TileLink masters -- Adding custom blackboxed verilog to a Chipyard design +- Adding custom blackboxed Verilog to a Chipyard design We also provide information on: diff --git a/docs/VLSI/Advanced-Usage.rst b/docs/VLSI/Advanced-Usage.rst index c7e1bae2..6ab44c02 100644 --- a/docs/VLSI/Advanced-Usage.rst +++ b/docs/VLSI/Advanced-Usage.rst @@ -5,11 +5,11 @@ Advanced Usage Alternative RTL Flows --------------------- -The Make-based build system provided supports using Hammer without using RTL generated by Chipyard. To push a custom verilog module through, one only needs to append the following environment variables to the ``make buildfile`` command (or edit them directly in the Makefile). +The Make-based build system provided supports using Hammer without using RTL generated by Chipyard. To push a custom Verilog module through, one only needs to append the following environment variables to the ``make buildfile`` command (or edit them directly in the Makefile). .. code-block:: shell - CUSTOM_VLOG= + CUSTOM_VLOG= VLSI_TOP= ``CUSTOM_VLOG`` breaks the dependency on the rest of the Chipyard infrastructure and does not start any Chisel/FIRRTL elaboration. ``VLSI_TOP`` selects the top module from your custom Verilog files. @@ -32,7 +32,7 @@ For ``make par``: ./example-vlsi -e /path/to/env.yml -p /path/to/syn-output-full.json -o /path/to/par-input.json --obj_dir /path/to/build syn-to-par ./example-vlsi -e /path/to/env.yml -p /path/to/par-input.json --obj_dir /path/to/build par - + A ``syn-to-par`` action translates the synthesis output configuration into an input configuration given by ``-o``. Then, this is passed to the ``par`` action. For more information about all the options that can be passed to the Hammer command-line driver, please see the Hammer documentation. diff --git a/docs/_static/images/chip-bringup.png b/docs/_static/images/chip-bringup.png index b7ed022648969b8749a642e1d2f5c66a377a1823..4e8d060271ceb46cd26c61a3d6dacd901fcf43f2 100644 GIT binary patch literal 18536 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 MRAuuYJq!H506YynlmGw# From 05f17f5b995f5de041569dbbb3bb2146902b14d6 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 23 Jan 2020 16:01:32 -0800 Subject: [PATCH 49/75] [tracegen] Add tracegen support for the BOOM L1D (#362) * [tracegen] Add tracegen support for the BOOM L1D * [tracegen] Split up BOOM Tracegen mixin and shim. * [ci] Fix tracegen hash for testing --- .circleci/config.yml | 62 ++++++ .circleci/defaults.sh | 1 + .circleci/run-tests.sh | 3 + build.sbt | 2 +- .../tracegen/src/main/scala/Configs.scala | 32 ++- .../tracegen/src/main/scala/System.scala | 15 +- generators/tracegen/src/main/scala/Tile.scala | 193 +++++++++++++++++- 7 files changed, 301 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6514fdb8..9fbb2958 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -346,6 +346,35 @@ jobs: key: tracegen-{{ .Branch }}-{{ .Revision }} paths: - "/home/riscvuser/project" + prepare-tracegen-boom: + docker: + - image: riscvboom/riscvboom-images:0.0.12 + environment: + JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit + TERM: dumb + steps: + - add_ssh_keys: + fingerprints: + - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" + - checkout + - run: + name: Create hash of toolchains + command: | + .circleci/create-hash.sh + - restore_cache: + keys: + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} + - restore_cache: + keys: + - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + - run: + name: Building the tracegen-boom subproject using Verilator + command: .circleci/do-rtl-build.sh tracegen-boom + no_output_timeout: 120m + - save_cache: + key: tracegen-boom-{{ .Branch }}-{{ .Revision }} + paths: + - "/home/riscvuser/project" prepare-firesim: docker: - image: riscvboom/riscvboom-images:0.0.12 @@ -593,6 +622,30 @@ jobs: - run: name: Run tracegen tests command: .circleci/run-tests.sh tracegen + tracegen-boom-run-tests: + docker: + - image: riscvboom/riscvboom-images:0.0.12 + environment: + JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit + TERM: dumb + steps: + - checkout + - run: + name: Create hash of toolchains + command: | + .circleci/create-hash.sh + - restore_cache: + keys: + - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - restore_cache: + keys: + - tracegen-boom-{{ .Branch }}-{{ .Revision }} + - restore_cache: + keys: + - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + - run: + name: Run tracegen-boom tests + command: .circleci/run-tests.sh tracegen-boom firesim-run-tests: docker: - image: riscvboom/riscvboom-images:0.0.12 @@ -723,6 +776,11 @@ workflows: - install-riscv-toolchain - install-verilator + - prepare-tracegen-boom: + requires: + - install-riscv-toolchain + - install-verilator + - prepare-firesim: requires: - install-riscv-toolchain @@ -770,6 +828,10 @@ workflows: requires: - prepare-tracegen + - tracegen-boom-run-tests: + requires: + - prepare-tracegen-boom + # Run the firesim tests - firesim-run-tests: requires: diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index c5838a48..08c4222c 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -49,5 +49,6 @@ mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=SimBlockDeviceRocketCo mapping["hwacha"]="SUB_PROJECT=example CONFIG=HwachaRocketConfig" mapping["gemmini"]="SUB_PROJECT=example CONFIG=GemminiRocketConfig" mapping["tracegen"]="SUB_PROJECT=tracegen CONFIG=NonBlockingTraceGenL2Config" +mapping["tracegen-boom"]="SUB_PROJECT=tracegen CONFIG=BoomTraceGenConfig" mapping["firesim"]="DESIGN=FireSim TARGET_CONFIG=DDR3FRFCFSLLC4MB_FireSimRocketChipConfig PLATFORM_CONFIG=BaseF1Config" mapping["fireboom"]="DESIGN=FireSim TARGET_CONFIG=DDR3FRFCFSLLC4MB_FireSimBoomConfig PLATFORM_CONFIG=BaseF1Config" diff --git a/.circleci/run-tests.sh b/.circleci/run-tests.sh index 97789b4c..6d01d182 100755 --- a/.circleci/run-tests.sh +++ b/.circleci/run-tests.sh @@ -65,6 +65,9 @@ case $1 in tracegen) run_tracegen ${mapping[$1]} ;; + tracegen-boom) + run_tracegen ${mapping[$1]} + ;; *) echo "No set of tests for $1. Did you spell it right?" exit 1 diff --git a/build.sbt b/build.sbt index d02c66bb..2fd83c55 100644 --- a/build.sbt +++ b/build.sbt @@ -127,7 +127,7 @@ lazy val example = conditionalDependsOn(project in file("generators/example")) .settings(commonSettings) lazy val tracegen = conditionalDependsOn(project in file("generators/tracegen")) - .dependsOn(rocketchip, sifive_cache) + .dependsOn(rocketchip, sifive_cache, boom) .settings(commonSettings) lazy val utilities = conditionalDependsOn(project in file("generators/utilities")) diff --git a/generators/tracegen/src/main/scala/Configs.scala b/generators/tracegen/src/main/scala/Configs.scala index e3536e6a..dd195296 100644 --- a/generators/tracegen/src/main/scala/Configs.scala +++ b/generators/tracegen/src/main/scala/Configs.scala @@ -32,9 +32,35 @@ class WithTraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) memStart = site(ExtMem).get.master.base, numGens = params.size) } - case MaxHartIdBits => if (params.size == 1) 1 else log2Ceil(params.size) + case MaxHartIdBits => log2Ceil(params.size + up(BoomTraceGenKey, site).length) max 1 }) +class WithBoomTraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) + extends Config((site, here, up) => { + case BoomTraceGenKey => params.map { dcp => TraceGenParams( + dcache = Some(dcp), + wordBits = site(XLen), + addrBits = 48, + addrBag = { + val nSets = dcp.nSets + val nWays = dcp.nWays + val blockOffset = site(SystemBusKey).blockOffset + val nBeats = min(2, site(SystemBusKey).blockBeats) + val beatBytes = site(SystemBusKey).beatBytes + List.tabulate(2 * nWays) { i => + Seq.tabulate(nBeats) { j => + BigInt((j * beatBytes) + ((i * nSets) << blockOffset)) + } + }.flatten + }, + maxRequests = nReqs, + memStart = site(ExtMem).get.master.base, + numGens = params.size) + } + case MaxHartIdBits => log2Ceil(params.size + up(TraceGenKey, site).length) max 1 +}) + + class TraceGenConfig extends Config( new WithTraceGen(List.fill(2) { DCacheParams(nMSHRs = 0, nSets = 16, nWays = 2) }) ++ new BaseConfig) @@ -43,6 +69,10 @@ class NonBlockingTraceGenConfig extends Config( new WithTraceGen(List.fill(2) { DCacheParams(nMSHRs = 2, nSets = 16, nWays = 2) }) ++ new BaseConfig) +class BoomTraceGenConfig extends Config( + new WithBoomTraceGen(List.fill(2) { DCacheParams(nMSHRs = 8, nSets = 16, nWays = 2) }) ++ + new BaseConfig) + class WithL2TraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) extends Config((site, here, up) => { case TraceGenKey => params.map { dcp => TraceGenParams( diff --git a/generators/tracegen/src/main/scala/System.scala b/generators/tracegen/src/main/scala/System.scala index 57d048a3..18307678 100644 --- a/generators/tracegen/src/main/scala/System.scala +++ b/generators/tracegen/src/main/scala/System.scala @@ -6,12 +6,18 @@ import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, BufferParams} import freechips.rocketchip.groundtest.{DebugCombiner, TraceGenParams} import freechips.rocketchip.subsystem._ -case object TraceGenKey extends Field[Seq[TraceGenParams]] +case object BoomTraceGenKey extends Field[Seq[TraceGenParams]](Nil) +case object TraceGenKey extends Field[Seq[TraceGenParams]](Nil) trait HasTraceGenTiles { this: BaseSubsystem => - val tiles = p(TraceGenKey).zipWithIndex.map { case (params, i) => + val rocket_tiles = p(TraceGenKey).zipWithIndex.map { case (params, i) => LazyModule(new TraceGenTile(i, params, p)) } + val boom_tiles = p(BoomTraceGenKey).zipWithIndex.map { case (params, i) => + LazyModule(new BoomTraceGenTile(i, params, p)) + } + + val tiles = rocket_tiles ++ boom_tiles tiles.foreach { t => sbus.fromTile(None, buffer = BufferParams.default) { t.masterNode } @@ -26,7 +32,10 @@ trait HasTraceGenTilesModuleImp extends LazyModuleImp { t.module.constants.hartid := i.U } - val status = DebugCombiner(outer.tiles.map(_.module.status)) + val status = DebugCombiner( + outer.rocket_tiles.map(_.module.status) ++ + outer.boom_tiles.map(_.module.status) + ) success := status.finished } diff --git a/generators/tracegen/src/main/scala/Tile.scala b/generators/tracegen/src/main/scala/Tile.scala index 1897224d..28974e1b 100644 --- a/generators/tracegen/src/main/scala/Tile.scala +++ b/generators/tracegen/src/main/scala/Tile.scala @@ -1,14 +1,19 @@ package tracegen import chisel3._ +import chisel3.util._ import freechips.rocketchip.config.Parameters import freechips.rocketchip.diplomacy.{LazyModule, SynchronousCrossing} import freechips.rocketchip.groundtest.{TraceGenerator, TraceGenParams, DummyPTW, GroundTestStatus} -import freechips.rocketchip.rocket.{DCache, NonBlockingDCache, SimpleHellaCacheIF} -import freechips.rocketchip.tile.{BaseTile, BaseTileModuleImp, HartsWontDeduplicate} +import freechips.rocketchip.rocket.{DCache, NonBlockingDCache, SimpleHellaCacheIF, HellaCacheExceptions, HellaCacheReq, HellaCacheIO} +import freechips.rocketchip.rocket.constants.{MemoryOpConstants} +import freechips.rocketchip.tile.{BaseTile, BaseTileModuleImp, HartsWontDeduplicate, TileKey} import freechips.rocketchip.tilelink.{TLInwardNode, TLIdentityNode} import freechips.rocketchip.interrupts._ +import boom.lsu.{BoomNonBlockingDCache, LSU, LSUCoreIO} +import boom.common.{BoomTileParams, MicroOp, BoomCoreParams, BoomModule} + class TraceGenTile(val id: Int, val params: TraceGenParams, q: Parameters) extends BaseTile(params, SynchronousCrossing(), HartsWontDeduplicate(params), q) { val dcache = params.dcache.map { dc => LazyModule( @@ -29,6 +34,190 @@ class TraceGenTile(val id: Int, val params: TraceGenParams, q: Parameters) override lazy val module = new TraceGenTileModuleImp(this) } +class BoomLSUShim(implicit p: Parameters) extends BoomModule()(p) + with MemoryOpConstants { + val io = IO(new Bundle { + val lsu = Flipped(new LSUCoreIO) + val tracegen = Flipped(new HellaCacheIO) + }) + + io.lsu.tsc_reg := 0.U(1.W) + + val rob_sz = numRobEntries + val rob = Reg(Vec(rob_sz, new HellaCacheReq)) + val rob_respd = RegInit(VecInit((~(0.U(rob_sz.W))).asBools)) + val rob_uop = Reg(Vec(rob_sz, new MicroOp)) + val rob_bsy = RegInit(VecInit(0.U(rob_sz.W).asBools)) + val rob_head = RegInit(0.U(log2Up(rob_sz).W)) + val rob_tail = RegInit(0.U(log2Up(rob_sz).W)) + val rob_wait_till_empty = RegInit(false.B) + val ready_for_amo = rob_tail === rob_head && io.lsu.fencei_rdy + when (ready_for_amo) { + rob_wait_till_empty := false.B + } + + def WrapInc(idx: UInt, max: Int): UInt = { + Mux(idx === (max-1).U, 0.U, idx + 1.U) + } + + + io.tracegen.req.ready := (!rob_bsy(rob_tail) && + !rob_wait_till_empty && + (ready_for_amo || !(isAMO(io.tracegen.req.bits.cmd) || io.tracegen.req.bits.cmd === M_XLR || io.tracegen.req.bits.cmd === M_XSC)) && + (WrapInc(rob_tail, rob_sz) =/= rob_head) && + !(io.lsu.ldq_full(0) && isRead(io.tracegen.req.bits.cmd)) && + !(io.lsu.stq_full(0) && isWrite(io.tracegen.req.bits.cmd)) + ) + + val tracegen_uop = WireInit((0.U).asTypeOf(new MicroOp)) + tracegen_uop.uses_ldq := isRead(io.tracegen.req.bits.cmd) && !isWrite(io.tracegen.req.bits.cmd) + tracegen_uop.uses_stq := isWrite(io.tracegen.req.bits.cmd) + tracegen_uop.rob_idx := rob_tail + tracegen_uop.uopc := io.tracegen.req.bits.tag + tracegen_uop.mem_size := io.tracegen.req.bits.size + tracegen_uop.mem_cmd := io.tracegen.req.bits.cmd + tracegen_uop.mem_signed := io.tracegen.req.bits.signed + tracegen_uop.ldq_idx := io.lsu.dis_ldq_idx(0) + tracegen_uop.stq_idx := io.lsu.dis_stq_idx(0) + tracegen_uop.is_amo := isAMO(io.tracegen.req.bits.cmd) || io.tracegen.req.bits.cmd === M_XSC + tracegen_uop.ctrl.is_load := isRead(io.tracegen.req.bits.cmd) && !isWrite(io.tracegen.req.bits.cmd) + tracegen_uop.ctrl.is_sta := isWrite(io.tracegen.req.bits.cmd) + tracegen_uop.ctrl.is_std := isWrite(io.tracegen.req.bits.cmd) + + io.lsu.dis_uops(0).valid := io.tracegen.req.fire() + io.lsu.dis_uops(0).bits := tracegen_uop + + when (io.tracegen.req.fire()) { + rob_tail := WrapInc(rob_tail, rob_sz) + rob_bsy(rob_tail) := true.B + rob_uop(rob_tail) := tracegen_uop + rob_respd(rob_tail) := false.B + rob(rob_tail) := io.tracegen.req.bits + when ( + isAMO(io.tracegen.req.bits.cmd) || + io.tracegen.req.bits.cmd === M_XLR || + io.tracegen.req.bits.cmd === M_XSC + ) { + rob_wait_till_empty := true.B + } + } + + io.lsu.fp_stdata.valid := false.B + io.lsu.fp_stdata.bits := DontCare + + + + io.lsu.commit.valids(0) := (!rob_bsy(rob_head) && rob_head =/= rob_tail && rob_respd(rob_head)) + io.lsu.commit.uops(0) := rob_uop(rob_head) + io.lsu.commit.rbk_valids(0) := false.B + io.lsu.commit.rollback := false.B + io.lsu.commit.fflags := DontCare + when (io.lsu.commit.valids(0)) { + rob_head := WrapInc(rob_head, rob_sz) + } + + when (io.lsu.clr_bsy(0).valid) { + rob_bsy(io.lsu.clr_bsy(0).bits) := false.B + } + when (io.lsu.clr_unsafe(0).valid && rob(io.lsu.clr_unsafe(0).bits).cmd =/= M_XLR) { + rob_bsy(io.lsu.clr_unsafe(0).bits) := false.B + } + when (io.lsu.exe(0).iresp.valid) { + rob_bsy(io.lsu.exe(0).iresp.bits.uop.rob_idx) := false.B + } + + + assert(!io.lsu.lxcpt.valid) + + io.lsu.exe(0).req.valid := RegNext(io.tracegen.req.fire()) + io.lsu.exe(0).req.bits := DontCare + io.lsu.exe(0).req.bits.uop := RegNext(tracegen_uop) + io.lsu.exe(0).req.bits.addr := RegNext(io.tracegen.req.bits.addr) + io.lsu.exe(0).req.bits.data := RegNext(io.tracegen.req.bits.data) + + io.tracegen.resp.valid := io.lsu.exe(0).iresp.valid + io.tracegen.resp.bits := DontCare + io.tracegen.resp.bits.tag := io.lsu.exe(0).iresp.bits.uop.uopc + io.tracegen.resp.bits.size := io.lsu.exe(0).iresp.bits.uop.mem_size + io.tracegen.resp.bits.data := io.lsu.exe(0).iresp.bits.data + + val store_resp_idx = PriorityEncoder((0 until rob_sz) map {i => + !rob_respd(i) && isWrite(rob(i).cmd) + }) + val can_do_store_resp = ~rob_respd(store_resp_idx) && isWrite(rob(store_resp_idx).cmd) && !isRead(rob(store_resp_idx).cmd) + when (can_do_store_resp && !io.lsu.exe(0).iresp.valid) { + rob_respd(store_resp_idx) := true.B + io.tracegen.resp.valid := true.B + io.tracegen.resp.bits.tag := rob(store_resp_idx).tag + } + + when (io.lsu.exe(0).iresp.valid) { + rob_respd(io.lsu.exe(0).iresp.bits.uop.rob_idx) := true.B + } + + io.lsu.exe(0).fresp.ready := true.B + io.lsu.exe(0).iresp.ready := true.B + + + io.lsu.exception := false.B + io.lsu.fence_dmem := false.B + + io.lsu.rob_pnr_idx := rob_tail + io.lsu.commit_load_at_rob_head := false.B + + io.lsu.brinfo := DontCare + io.lsu.brinfo.valid := false.B + io.lsu.rob_head_idx := rob_head + + +} + +class BoomTraceGenTile(val id: Int, val params: TraceGenParams, q: Parameters) + extends BaseTile(params, SynchronousCrossing(), HartsWontDeduplicate(params), q) { + val boom_params = p.alterMap(Map(TileKey -> BoomTileParams( + dcache=params.dcache, + core=BoomCoreParams(nPMPs=0, numLdqEntries=32, numStqEntries=32, useVM=false)))) + val dcache = LazyModule(new BoomNonBlockingDCache(hartId)(boom_params)) + + val intInwardNode: IntInwardNode = IntIdentityNode() + val intOutwardNode: IntOutwardNode = IntIdentityNode() + val slaveNode: TLInwardNode = TLIdentityNode() + val ceaseNode: IntOutwardNode = IntIdentityNode() + val haltNode: IntOutwardNode = IntIdentityNode() + val wfiNode: IntOutwardNode = IntIdentityNode() + + val masterNode = visibilityNode + masterNode := dcache.node + + override lazy val module = new BoomTraceGenTileModuleImp(this) +} + +class BoomTraceGenTileModuleImp(outer: BoomTraceGenTile) + extends BaseTileModuleImp(outer){ + + val status = IO(new GroundTestStatus) + + val tracegen = Module(new TraceGenerator(outer.params)) + tracegen.io.hartid := constants.hartid + + val ptw = Module(new DummyPTW(1)) + val lsu = Module(new LSU()(outer.boom_params, outer.dcache.module.edge)) + val boom_shim = Module(new BoomLSUShim()(outer.boom_params)) + ptw.io.requestors.head <> lsu.io.ptw + outer.dcache.module.io.lsu <> lsu.io.dmem + boom_shim.io.tracegen <> tracegen.io.mem + boom_shim.io.lsu <> lsu.io.core + + // Normally the PTW would use this port + lsu.io.hellacache := DontCare + lsu.io.hellacache.req.valid := false.B + + status.finished := tracegen.io.finished + status.timeout.valid := tracegen.io.timeout + status.timeout.bits := 0.U + status.error.valid := false.B +} + class TraceGenTileModuleImp(outer: TraceGenTile) extends BaseTileModuleImp(outer) { val status = IO(new GroundTestStatus) From 961f42bb2d6ba6e98d71baaa0d8091b701a8f3a1 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 23 Jan 2020 17:06:09 -0800 Subject: [PATCH 50/75] Bump gemmini and the Spike simulator in esp-tools (#394) --- generators/gemmini | 2 +- toolchains/esp-tools/riscv-isa-sim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generators/gemmini b/generators/gemmini index 16fda885..6602434b 160000 --- a/generators/gemmini +++ b/generators/gemmini @@ -1 +1 @@ -Subproject commit 16fda88555be77df41a6c0687f64810417843dae +Subproject commit 6602434b34fb33d005af50cd5e7bf8534f82ebf7 diff --git a/toolchains/esp-tools/riscv-isa-sim b/toolchains/esp-tools/riscv-isa-sim index 5965f8fc..9163c430 160000 --- a/toolchains/esp-tools/riscv-isa-sim +++ b/toolchains/esp-tools/riscv-isa-sim @@ -1 +1 @@ -Subproject commit 5965f8fcdbe931d6f8acabdea53c1e3a7b54e3f4 +Subproject commit 9163c430be06d43dc0ecc43698791fc36cc3402d From 5da86669513edf003021e2147c1ae46c28714f31 Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Thu, 23 Jan 2020 18:05:58 -0800 Subject: [PATCH 51/75] bump firesim (#395) --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index 5f6bd4fa..19f75c8b 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 5f6bd4fa16af5d2fc15c49b54358f57dbd2c1469 +Subproject commit 19f75c8bea79d581231dd98f9b91162de2557521 From 3fe0460a807ecf5f119c0f32c0236c8fe2b55117 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 23 Jan 2020 18:06:28 -0800 Subject: [PATCH 52/75] enforce that macrocompiler passes are done serially (#392) --- common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.mk b/common.mk index 98ee2bb1..2259bb40 100644 --- a/common.mk +++ b/common.mk @@ -82,7 +82,7 @@ HARNESS_MACROCOMPILER_MODE = --mode synflops $(HARNESS_SMEMS_FILE) $(HARNESS_SMEMS_FIR): harness_macro_temp @echo "" > /dev/null -harness_macro_temp: $(HARNESS_SMEMS_CONF) +harness_macro_temp: $(HARNESS_SMEMS_CONF) | top_macro_temp cd $(base_dir) && $(SBT) "project barstoolsMacros" "runMain barstools.macros.MacroCompiler -n $(HARNESS_SMEMS_CONF) -v $(HARNESS_SMEMS_FILE) -f $(HARNESS_SMEMS_FIR) $(HARNESS_MACROCOMPILER_MODE)" ######################################################################################## From 5ceb2cc69a6315b0f2a61455a5386756dbd790fc Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 23 Jan 2020 18:24:46 -0800 Subject: [PATCH 53/75] boom bump (#397) --- generators/boom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/boom b/generators/boom index 63b430bf..a88fe70c 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit 63b430bf350fd2c272ca6b42b0a797770205ad06 +Subproject commit a88fe70c81c33fb4773d52a529633029fa6eb9af From 24bf2ed2b580d7b6206191e5d51c0595315a888a Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 23 Jan 2020 18:36:56 -0800 Subject: [PATCH 54/75] bump sha3 and testchipip (#398) --- generators/sha3 | 2 +- generators/testchipip | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generators/sha3 b/generators/sha3 index faf08c0f..543adb4f 160000 --- a/generators/sha3 +++ b/generators/sha3 @@ -1 +1 @@ -Subproject commit faf08c0f39593b1005398830cc825bec43c0a610 +Subproject commit 543adb4ff1ac8b4f21f8d3ac5f7e865f8d109731 diff --git a/generators/testchipip b/generators/testchipip index 62cf2629..c11549ba 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 62cf2629a7f2df054224c7dfbb9ff84b9e2b1203 +Subproject commit c11549ba30483ee3c0d331fb893c45814bdb6b63 From 93fb06a55f42cb6260853aafcbd203a9c30fb150 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 23 Jan 2020 19:01:40 -0800 Subject: [PATCH 55/75] bump icenet to master branch commit --- generators/icenet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/icenet b/generators/icenet index 2874db7f..49b6dfb6 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit 2874db7fdc5bee81074bdfe9cbbd4f68a9881943 +Subproject commit 49b6dfb6341bf128e95c549e42f881ad16dd45a5 From ca653c03053b8c91ff3a2b8e051538a200fd2e62 Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Thu, 23 Jan 2020 19:18:42 -0800 Subject: [PATCH 56/75] Fix changelog formatting (#400) --- CHANGELOG.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 935c72f6..d364bf0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ -[1.0.0] - 2019-10-11 -Added -This repository used to be "project-template", a template for Chisel-based projects. Through tighter integration of multiple projects from the Berkeley Architecture Research group at UC Berkeley, this repository is re-released as Chipyard - a framework for agile hardware development of RISC-V based Systems-on-Chip. +# Changelog + +This changelog follows the format defined here: https://keepachangelog.com/en/1.0.0/ + +## [1.0.0] - 2019-10-19 + +### Added + +* This repository used to be "project-template", a template for Chisel-based projects. Through tighter integration of multiple projects from the Berkeley Architecture Research group at UC Berkeley, this repository is re-released as Chipyard - a framework for agile hardware development of RISC-V based Systems-on-Chip. From d7d7c79c22cc2aa982da67725ec096fc5e616219 Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Fri, 24 Jan 2020 09:31:41 -0800 Subject: [PATCH 57/75] scripts: Initialize firesim non-recursively (#388) --- scripts/init-submodules-no-riscv-tools.sh | 42 +++++++---------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/scripts/init-submodules-no-riscv-tools.sh b/scripts/init-submodules-no-riscv-tools.sh index 28f64c58..67e74e99 100755 --- a/scripts/init-submodules-no-riscv-tools.sh +++ b/scripts/init-submodules-no-riscv-tools.sh @@ -6,25 +6,6 @@ set -o pipefail RDIR=$(git rev-parse --show-toplevel) -_usage() { - echo "usage: ${0} [--no-firesim]" >&2 - exit 1 -} - -NO_FIRESIM=false -while getopts 'h-:' opt ; do - case ${opt} in - -) - case ${OPTARG} in - no-firesim) NO_FIRESIM=true ;; - *) echo "invalid option: --${OPTARG}" >&2 ; _usage ;; - esac ;; - h) _usage ;; - *) echo "invalid option: -${opt}" >&2 ; _usage ;; - esac -done -shift $((OPTIND - 1)) - # Ignore toolchain submodules cd "$RDIR" for name in toolchains/*-tools/*/ ; do @@ -56,16 +37,17 @@ git config --unset submodule.vlsi/hammer-synopsys-plugins.update git config --unset submodule.vlsi/hammer-mentor-plugins.update git config --unset submodule.generators/sha3.update -# Shallow clone by default (recursive clone would get linux) +# Non-recursive clone to exclude riscv-linux git submodule update --init generators/sha3 -if [ $NO_FIRESIM = false ]; then - echo "initializing firesim" - # Renable firesim and init only the required submodules to provide - # all required scala deps, without doing a full build-setup - git config --unset submodule.sims/firesim.update - git submodule update --init sims/firesim - git -C sims/firesim submodule update --init sim/midas - git -C sims/firesim submodule update --init --recursive sw/firesim-software - git config submodule.sims/firesim.update none -fi +git config --unset submodule.sims/firesim.update +# Minimal non-recursive clone to initialize sbt dependencies +git submodule update --init sims/firesim +( + cd sims/firesim + # Initialize dependencies for MIDAS-level RTL simulation + git submodule update --init sim/midas + # Exclude riscv-linux + git submodule update --init sw/firesim-software +) +git config submodule.sims/firesim.update none From 810db31abdb2bd38bd073856018c2d361ed0b6c8 Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Fri, 24 Jan 2020 09:52:56 -0800 Subject: [PATCH 58/75] bump firesim (#402) --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index 19f75c8b..1554acea 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 19f75c8bea79d581231dd98f9b91162de2557521 +Subproject commit 1554acea9e863515da1a5f090def643d023db2dd From 8b7796a5c8134a229fc3e60f7b85565b32493a23 Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Sat, 25 Jan 2020 16:50:20 -0800 Subject: [PATCH 59/75] Add pubs for non-docs descriptions of components (#405) * Add pubs for non-docs descriptions of components --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 2ef59584..4efaf320 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,29 @@ Chipyard is actively developed in the [Berkeley Architecture Research Group][ucb * See [CONTRIBUTING.md](/CONTRIBUTING.md) +## Chipyard-related Publications + +These publications cover many of the internal components used in Chipyard. However, for the most up-to-date usage instructions, users should refer to the Chipyard docs. + +* **Generators** + * **Rocket Chip**: K. Asanovic, et al., *UCB EECS TR*. [PDF](http://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-17.pdf). + * **BOOM**: C. Celio, et al., *Hot Chips 30*. [PDF](https://www.hotchips.org/hc30/1conf/1.03_Berkeley_BROOM_HC30.Berkeley.Celio.v02.pdf). + * **Hwacha**: Y. Lee, et al., *ESSCIRC'14*. [PDF](http://hwacha.org/papers/riscv-esscirc2014.pdf). + * **Gemmini**: H. Genc, et al., *arXiv*. [PDF](https://arxiv.org/pdf/1911.09925). +* **Sims** + * **FireSim**: S. Karandikar, et al., *ISCA'18*. [PDF](https://sagark.org/assets/pubs/firesim-isca2018.pdf). + * **FireSim Micro Top Picks**: S. Karandikar, et al., *IEEE Micro, Top Picks 2018*. [PDF](https://sagark.org/assets/pubs/firesim-micro-top-picks2018.pdf). + * **FASED**: D. Biancolin, et al., *FPGA'19*. [PDF](https://people.eecs.berkeley.edu/~biancolin/papers/fased-fpga19.pdf). + * **Golden Gate**: A. Magyar, et al., *ICCAD'19*. [PDF](https://davidbiancolin.github.io/papers/goldengate-iccad19.pdf). + * **FirePerf**: S. Karandikar, et al., *ASPLOS'20*. [PDF](https://sagark.org/assets/pubs/fireperf-asplos2020.pdf). +* **Tools** + * **Chisel**: J. Bachrach, et al., *DAC'12*. [PDF](https://people.eecs.berkeley.edu/~krste/papers/chisel-dac2012.pdf). + * **FIRRTL**: A. Izraelevitz, et al., *ICCAD'17*. [PDF](https://ieeexplore.ieee.org/document/8203780). + * **Chisel DSP**: A. Wang, et al., *DAC'18*. [PDF](https://ieeexplore.ieee.org/document/8465790). +* **VLSI** + * **Hammer**: E. Wang, et al., *ISQED'20*. [PDF](https://www.isqed.org/English/Archives/2020/Technical_Sessions/113.html). + + [hwacha]:http://hwacha.org [hammer]:https://github.com/ucb-bar/hammer From b6c7d590326e38158e32f0226ad54660a150a3f9 Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Sat, 25 Jan 2020 16:51:24 -0800 Subject: [PATCH 60/75] Start prepping changelog for 1.1.0 (#403) * Changelog for 1.1.0 --- CHANGELOG.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d364bf0e..31fb2250 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,49 @@ This changelog follows the format defined here: https://keepachangelog.com/en/1.0.0/ +## [1.1.0] - 2020-01-25 + +A more detailed account of everything included is included in the dev to master PR for this release: https://github.com/ucb-bar/chipyard/pull/367 + +### Added +* Gemmini generator and config (PR #356 ) +* Coremark + SPEC2017 benchmarks (PR #326, #338, #344) +* Add Hwacha tests to CI (PR #284) +* Add Hwacha tests to benchmark and assembly test suites (PR #284) +* Added Hwacha + Large Boom Config (PR #315) +* Add multi-core config with a small Rocket core attached on the side (PR #361 ) +* Add UART and Test Harness UART Adapter to all configurations (PR #348) +* User can specify $RISCV directory in build-toolchains.sh (PR #334) +* Checksum offload in IceNet (PR #364) + +### Changed +* Rocketchip bumped to commit [4f0cdea](https://github.com/chipsalliance/rocket-chip/tree/4f0cdea85c8a2b849fd582ccc8497892001d06b0), for chisel version 3.2.0 which includes Async reset support +* FireSim release 1.8.0 +* FireMarshal release 1.8.0 +* BOOM release 2.2.3 (PR #397) +* baremetal software toolchains, using libgloss and newlib instead of in-house syscalls. +* Add toolchain specific `env.sh` (PR #304) +* `run-binary`-like interface now dumps `.log` (stdout) and `.out` (stderr) files (PR #308) +* Split the VLSI build dir on type of design (PR #331) +* Reduce Ctags runtime and only look at scala, C, C++, and Python files (PR #346) +* Top/Top-level-traits now behave as a configurable generator (PR #347) +* Test suite makefrag generator includes Hwacha test suites (PR #342) + +### Fixed +* Fix VLSI makefile requirements for SRAM generation (PR #318) +* Only filter header files from common simulation files (PR #322) +* Bump MacroCompiler for bugfixes (PR #332) +* commit-on-master check has specific behavior based on source branch (PR #345) +* Makefile filtering of blackbox resource files only omits .h files (PR #322) +* Parallel make fixed (PR #386 #392) + +### Deprecated +* No longer need to specify `WithXTop`, default `Top` is a generator for all `Top`s (PR #347) + +### Removed +* N/A + + ## [1.0.0] - 2019-10-19 ### Added From a751b9c2134022c0e6d4e41e3405b90ac70b0782 Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Sat, 25 Jan 2020 16:54:36 -0800 Subject: [PATCH 61/75] bump firesim (#406) --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index 1554acea..771b60a0 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 1554acea9e863515da1a5f090def643d023db2dd +Subproject commit 771b60a08b4f916beb05a9195b1e0238335db839 From 1a163310656d392728ec2dbe7a4a913dc9667d4a Mon Sep 17 00:00:00 2001 From: alonamid Date: Sat, 25 Jan 2020 16:58:21 -0800 Subject: [PATCH 62/75] Update README.md (#407) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4efaf320..26f32cf5 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Chipyard is actively developed in the [Berkeley Architecture Research Group][ucb ## Chipyard-related Publications -These publications cover many of the internal components used in Chipyard. However, for the most up-to-date usage instructions, users should refer to the Chipyard docs. +These publications cover many of the internal components used in Chipyard. However, for the most up-to-date details, users should refer to the Chipyard docs. * **Generators** * **Rocket Chip**: K. Asanovic, et al., *UCB EECS TR*. [PDF](http://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-17.pdf). From e89a0c3d2f175438fc05b7b420c92747fed5d826 Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Sat, 25 Jan 2020 19:11:21 -0800 Subject: [PATCH 63/75] Bump to FireSim Master 1.8.0 (#408) * bump to firesim master 1.8.0 --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index 771b60a0..b4951f25 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 771b60a08b4f916beb05a9195b1e0238335db839 +Subproject commit b4951f2589114e3849c77c798982afd10fc11b3e From 18775982d3de1b08d6fb3a591802e0711c86dc8d Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Sun, 26 Jan 2020 09:44:44 -0800 Subject: [PATCH 64/75] Don't hardcode version in docs conf.py, let readthedocs fill it in --- docs/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index fd6139fe..f4a3272b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -61,9 +61,9 @@ author = u'Berkeley Architecture Research' # built documents. # # The short X.Y version. -version = u'0.1' +version = u'' # The full version, including alpha/beta/rc tags. -release = u'0.1' +release = u'' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From 0225ab7b5159bfe0b7d9487c6919c316f98cb5a6 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 28 Jan 2020 15:35:18 -0800 Subject: [PATCH 65/75] bump sifive-cache for updated gitignore (#411) --- generators/sifive-cache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/sifive-cache b/generators/sifive-cache index f5a09e28..d3d95ece 160000 --- a/generators/sifive-cache +++ b/generators/sifive-cache @@ -1 +1 @@ -Subproject commit f5a09e289b92e53039d74114140d0380032ad8b4 +Subproject commit d3d95ece5a570b423892bede4fed6cb0030c7701 From 14c4c62eeae6d65c2f3c1a6304994dbaa0527a70 Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Tue, 28 Jan 2020 16:38:44 -0800 Subject: [PATCH 66/75] [ci-skip] Gitignore generated env-riscv-tools.sh (#414) * Gitignore generated {env,esp}-riscv-tools.sh [ci-skip] --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 7c1463a4..e2c66082 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ riscv-tools-install esp-tools-install tags *~ +env-riscv-tools.sh +env-esp-tools.sh From b8104904210af0e65ff6ec456f24a5c8711c3836 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Tue, 28 Jan 2020 16:39:39 -0800 Subject: [PATCH 67/75] [example] fix multi-rocc boom+rocket+hwacha config (#413) --- generators/example/src/main/scala/HeteroConfigs.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generators/example/src/main/scala/HeteroConfigs.scala b/generators/example/src/main/scala/HeteroConfigs.scala index d68532ad..ff3bf338 100644 --- a/generators/example/src/main/scala/HeteroConfigs.scala +++ b/generators/example/src/main/scala/HeteroConfigs.scala @@ -92,7 +92,8 @@ class DualLargeBoomAndHwachaRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNoMMIOPort ++ new freechips.rocketchip.subsystem.WithNoSlavePort ++ new WithMultiRoCC ++ // support heterogeneous rocc - new WithMultiRoCCHwacha(2) ++ // put hwacha on hart-2 (rocket) + new WithMultiRoCCHwacha(2) ++ // override: put hwacha on hart-2 (rocket) + new hwacha.DefaultHwachaConfig ++ // setup hwacha on all harts new boom.common.WithRenumberHarts ++ new boom.common.WithLargeBooms ++ new boom.common.WithNBoomCores(2) ++ From 5d27ac5bbc12047ab379fa16f4e27015d24f7dfa Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 30 Jan 2020 10:08:53 -0800 Subject: [PATCH 68/75] [sim] Pipe /dev/null to simulators to fix VCS messing up stdout (#417) --- common.mk | 12 ++++++------ sims/vcs/Makefile | 2 +- sims/verilator/Makefile | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/common.mk b/common.mk index 2259bb40..1fd7a193 100644 --- a/common.mk +++ b/common.mk @@ -102,19 +102,19 @@ verilog: $(sim_vsrcs) ######################################################################################### .PHONY: run-binary run-binary-fast run-binary-debug run-fast run-binary: $(sim) - (set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $(BINARY) 2> >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log) + (set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $(BINARY) >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log) ######################################################################################### # helper rules to run simulator as fast as possible ######################################################################################### run-binary-fast: $(sim) - (set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(PERMISSIVE_OFF) $(BINARY) | tee $(sim_out_name).log) + (set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(PERMISSIVE_OFF) $(BINARY) >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log) + (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) $(WAVEFORM_FLAG) $(PERMISSIVE_OFF) $(BINARY) >(spike-dasm > $(sim_out_name).out) | tee $(sim_out_name).log) run-fast: run-asm-tests-fast run-bmark-tests-fast @@ -126,10 +126,10 @@ $(output_dir)/%: $(RISCV)/riscv64-unknown-elf/share/riscv-tests/isa/% ln -sf $< $@ $(output_dir)/%.run: $(output_dir)/% $(sim) - (set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(PERMISSIVE_OFF) $< | tee $<.log) && touch $@ + (set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(PERMISSIVE_OFF) $< >(spike-dasm > $@) | tee $<.log) + (set -o pipefail && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) $< >(spike-dasm > $@) | tee $<.log) ######################################################################################### # include build/project specific makefrags made from the generator @@ -149,7 +149,7 @@ $(AXE): $(wildcard $(AXE_DIR)/*.[ch]) $(AXE_DIR)/make.sh cd $(AXE_DIR) && ./make.sh $(output_dir)/tracegen.out: $(sim) - mkdir -p $(output_dir) && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) none 2> $@ + mkdir -p $(output_dir) && $(sim) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(VERBOSE_FLAGS) $(PERMISSIVE_OFF) none $@ $(output_dir)/tracegen.result: $(output_dir)/tracegen.out $(AXE) $(base_dir)/scripts/check-tracegen.sh $< > $@ diff --git a/sims/vcs/Makefile b/sims/vcs/Makefile index f9bb8ca9..86c28f23 100644 --- a/sims/vcs/Makefile +++ b/sims/vcs/Makefile @@ -91,7 +91,7 @@ $(sim_debug) : $(sim_vsrcs) $(sim_common_files) ######################################################################################### .PRECIOUS: $(output_dir)/%.vpd %.vpd $(output_dir)/%.vpd: $(output_dir)/% $(sim_debug) - (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< 2> >(spike-dasm > $<.out) | tee $<.log) + (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< >(spike-dasm > $<.out) | tee $<.log) ######################################################################################### # general cleanup rule diff --git a/sims/verilator/Makefile b/sims/verilator/Makefile index 364d68fd..caaba672 100644 --- a/sims/verilator/Makefile +++ b/sims/verilator/Makefile @@ -110,7 +110,7 @@ $(sim_debug): $(model_mk_debug) $(output_dir)/%.vpd: $(output_dir)/% $(sim_debug) rm -f $@.vcd && mkfifo $@.vcd vcd2vpd $@.vcd $@ > /dev/null & - (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) -v$@.vcd $(PERMISSIVE_OFF) $< 2> >(spike-dasm > $<.out) | tee $<.log) + (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) -v$@.vcd $(PERMISSIVE_OFF) $< >(spike-dasm > $<.out) | tee $<.log) ######################################################################################### # general cleanup rule From 59dd6a79ff00a25c681ef26953fb3c4ea589f5e1 Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Thu, 30 Jan 2020 15:26:00 -0800 Subject: [PATCH 69/75] [firechip] Enable trace by default in BOOM-based targets (#412) * [firechip] Enable trace by default in BOOM-based targets * Bump boom for trace enchancements --- generators/boom | 2 +- generators/firechip/src/main/scala/TargetConfigs.scala | 5 +++++ generators/firechip/src/main/scala/TargetMixins.scala | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/generators/boom b/generators/boom index a88fe70c..1d4d0cda 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit a88fe70c81c33fb4773d52a529633029fa6eb9af +Subproject commit 1d4d0cda50969a0c46f1807cc7b2201bbf42a6f3 diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 17ac06e6..ed2a86c5 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -80,6 +80,10 @@ class WithBoomL2TLBs(entries: Int) extends Config((site, here, up) => { )) }) +class WithBoomEnableTrace extends Config((site, here, up) => { + case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy(trace = true)) +}) + // Disables clock-gating; doesn't play nice with our FAME-1 pass class WithoutClockGating extends Config((site, here, up) => { case DebugModuleKey => up(DebugModuleKey, site).map(_.copy(clockGate = false)) @@ -176,6 +180,7 @@ class FireSimBoomConfig extends Config( new WithNICKey ++ new WithSerial ++ new WithBlockDevice ++ + new WithBoomEnableTrace ++ new WithBoomL2TLBs(1024) ++ new WithoutClockGating ++ new WithDefaultMemModel ++ diff --git a/generators/firechip/src/main/scala/TargetMixins.scala b/generators/firechip/src/main/scala/TargetMixins.scala index c3982d95..be93bb7a 100644 --- a/generators/firechip/src/main/scala/TargetMixins.scala +++ b/generators/firechip/src/main/scala/TargetMixins.scala @@ -45,7 +45,7 @@ trait HasTraceIOImp extends LazyModuleImp { // Enabled to test TracerV trace capture if (p(PrintTracePort)) { val traceprint = Wire(UInt(512.W)) - traceprint := Cat(traceIO.traces.map(_.asUInt)) + traceprint := Cat(traceIO.traces.map(_.reverse.asUInt)) printf("TRACEPORT: %x\n", traceprint) } } From 3e4c99e044cb548a7cc8db75d0a0437f182c2655 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Tue, 4 Feb 2020 18:33:08 -0800 Subject: [PATCH 70/75] [ci] use re-usable config. components (#421) --- .circleci/config.yml | 832 ++++++++++++------------------------------- 1 file changed, 221 insertions(+), 611 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9fbb2958..8a1fdb48 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,16 +1,142 @@ # CircleCI Configuration File # version of circleci -version: 2 +version: 2.1 -# set of jobs to run -jobs: - commit-on-master-check: +parameters: + verilator-cache-version: + type: string + default: "v3" + tools-cache-version: + type: string + default: "v4" + +# default execution env.s +executors: + main-env: docker: - image: riscvboom/riscvboom-images:0.0.12 environment: JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + +# re-usable commands +commands: + toolchain-build: + description: "Build a toolchain" + parameters: + tools-version: + type: string + default: "riscv-tools" + steps: + - checkout + - run: + name: Create hash of toolchains + command: | + .circleci/create-hash.sh + - restore_cache: + keys: + - << parameters.tools-version >>-installed-<< pipeline.parameters.tools-cache-version >>-{{ checksum "../<< parameters.tools-version >>.hash" }} + - run: + name: Building << parameters.tools-version >> + command: | + .circleci/build-toolchains.sh << parameters.tools-version >> + no_output_timeout: 120m + - save_cache: + key: << parameters.tools-version >>-installed-<< pipeline.parameters.tools-cache-version >>-{{ checksum "../<< parameters.tools-version >>.hash" }} + paths: + - "/home/riscvuser/<< parameters.tools-version >>-install" + + ssh-checkout: + description: "Add SSH key and checkout code" + steps: + - add_ssh_keys: + fingerprints: + - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" + - checkout + + setup-tools-verilator: + description: "Get toolchain and verilator" + parameters: + tools-version: + type: string + default: "riscv-tools" + steps: + - ssh-checkout + - run: + name: Create hash of toolchains + command: | + .circleci/create-hash.sh + - restore_cache: + keys: + - << parameters.tools-version >>-installed-<< pipeline.parameters.tools-cache-version >>-{{ checksum "../<< parameters.tools-version >>.hash" }} + - restore_cache: + keys: + - verilator-installed-<< pipeline.parameters.verilator-cache-version >>-{{ checksum "sims/verilator/verilator.mk" }} + + prepare-rtl: + description: "Run the prepare step of RTL" + parameters: + tools-version: + type: string + default: "riscv-tools" + project-key: + type: string + timeout: + type: string + default: "120m" + build-script: + type: string + default: "do-rtl-build.sh" + steps: + - setup-tools-verilator: + tools-version: "<< parameters.tools-version >>" + - run: + name: Building << parameters.project-key >> subproject using Verilator + command: .circleci/<< parameters.build-script >> << parameters.project-key >> + no_output_timeout: << parameters.timeout >> + - save_cache: + key: << parameters.project-key >>-{{ .Branch }}-{{ .Revision }} + paths: + - "/home/riscvuser/project" + + run-tests: + description: "Run a set of tests" + parameters: + tools-version: + type: string + default: "riscv-tools" + project-key: + type: string + extra-cache-restore: + type: string + default: "" + run-script: + type: string + default: "run-tests.sh" + timeout: + type: string + default: "10m" + steps: + - setup-tools-verilator: + tools-version: "<< parameters.tools-version >>" + - restore_cache: + keys: + - << parameters.project-key >>-{{ .Branch }}-{{ .Revision }} + - when: + condition: << parameters.extra-cache-restore >> + steps: + - restore_cache: + keys: + - << parameters.extra-cache-restore >>-{{ .Branch }}-{{ .Revision }} + - run: + name: Run << parameters.project-key >> subproject tests + command: .circleci/<< parameters.run-script >> << parameters.project-key >> + no_output_timeout: << parameters.timeout >> + +# set of jobs to run +jobs: + commit-on-master-check: + executor: main-env steps: - checkout - run: @@ -18,94 +144,42 @@ jobs: command: | .circleci/check-commit.sh install-riscv-toolchain: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - run: - name: Building riscv-tools toolchain - command: | - .circleci/build-toolchains.sh riscv-tools - no_output_timeout: 120m - - save_cache: - key: riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - paths: - - "/home/riscvuser/riscv-tools-install" + - toolchain-build: + tools-version: "riscv-tools" install-esp-toolchain: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - - run: - name: Building esp-tools toolchain - command: | - .circleci/build-toolchains.sh esp-tools - no_output_timeout: 120m - - save_cache: - key: esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - paths: - - "/home/riscvuser/esp-tools-install" + - toolchain-build: + tools-version: "esp-tools" install-verilator: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout + - ssh-checkout - restore_cache: keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + - verilator-installed-<< pipeline.parameters.verilator-cache-version >>-{{ checksum "sims/verilator/verilator.mk" }} - run: name: Build Verilator command: | .circleci/build-verilator.sh no_output_timeout: 120m - save_cache: - key: verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + key: verilator-installed-<< pipeline.parameters.verilator-cache-version >>-{{ checksum "sims/verilator/verilator.mk" }} paths: - "/home/riscvuser/verilator" build-extra-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout + - ssh-checkout - run: name: Create hash of toolchains command: | .circleci/create-hash.sh - restore_cache: keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} + - riscv-tools-installed-<< pipeline.parameters.tools-cache-version >>-{{ checksum "../riscv-tools.hash" }} - run: name: Build extra tests command: .circleci/build-extra-tests.sh @@ -115,593 +189,129 @@ jobs: paths: - "/home/riscvuser/project/tests" prepare-example: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the example subproject using Verilator - command: .circleci/do-rtl-build.sh example - no_output_timeout: 120m - - save_cache: - key: example-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + project-key: "example" prepare-boomrocketexample: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the boomrocketexample subproject using Verilator - command: .circleci/do-rtl-build.sh boomrocketexample - no_output_timeout: 240m - - save_cache: - key: boomrocketexample-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + project-key: "boomrocketexample" + timeout: "240m" prepare-boom: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the boom subproject using Verilator - command: .circleci/do-rtl-build.sh boom - no_output_timeout: 120m - - save_cache: - key: boom-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + project-key: "boom" prepare-rocketchip: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the rocketchip subproject using Verilator - command: .circleci/do-rtl-build.sh rocketchip - no_output_timeout: 120m - - save_cache: - key: rocketchip-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + project-key: "rocketchip" prepare-blockdevrocketchip: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the blockdevrocketchip subproject using Verilator - command: .circleci/do-rtl-build.sh blockdevrocketchip - no_output_timeout: 120m - - save_cache: - key: blockdevrocketchip-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + project-key: "blockdevrocketchip" prepare-hwacha: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the hwacha subproject using Verilator - command: .circleci/do-rtl-build.sh hwacha - no_output_timeout: 120m - - save_cache: - key: hwacha-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + tools-version: "esp-tools" + project-key: "hwacha" prepare-gemmini: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the gemmini subproject using Verilator - command: .circleci/do-rtl-build.sh gemmini - no_output_timeout: 120m - - save_cache: - key: gemmini-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + tools-version: "esp-tools" + project-key: "gemmini" prepare-tracegen: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the tracegen subproject using Verilator - command: .circleci/do-rtl-build.sh tracegen - no_output_timeout: 120m - - save_cache: - key: tracegen-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + project-key: "tracegen" prepare-tracegen-boom: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the tracegen-boom subproject using Verilator - command: .circleci/do-rtl-build.sh tracegen-boom - no_output_timeout: 120m - - save_cache: - key: tracegen-boom-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + project-key: "tracegen-boom" prepare-firesim: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building FireSim MIDAS simulator using Verilator - command: .circleci/do-firesim-build.sh firesim - no_output_timeout: 120m - - save_cache: - key: firesim-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + project-key: "firesim" + build-script: "do-firesim-build.sh" prepare-fireboom: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - add_ssh_keys: - fingerprints: - - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building FireSim MIDAS simulator using Verilator - command: .circleci/do-firesim-build.sh fireboom - no_output_timeout: 120m - - save_cache: - key: fireboom-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" + - prepare-rtl: + project-key: "fireboom" + build-script: "do-firesim-build.sh" midasexamples-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + - setup-tools-verilator - run: name: Run midasexamples tests command: .circleci/run-midasexamples-tests.sh example-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - example-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run example tests - command: .circleci/run-tests.sh example + - run-tests: + project-key: "example" boomrocketexample-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - boomrocketexample-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run boomrocketexample tests - command: .circleci/run-tests.sh boomrocketexample + - run-tests: + project-key: "boomrocketexample" boom-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - boom-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run boom tests - command: .circleci/run-tests.sh boom + - run-tests: + project-key: "boom" rocketchip-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - rocketchip-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run rocketchip tests - command: .circleci/run-tests.sh rocketchip + - run-tests: + project-key: "rocketchip" hwacha-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - - restore_cache: - keys: - - hwacha-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run hwacha tests - command: .circleci/run-tests.sh hwacha + - run-tests: + tools-version: "esp-tools" + project-key: "hwacha" gemmini-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - esp-tools-installed-v4-{{ checksum "../esp-tools.hash" }} - - restore_cache: - keys: - - gemmini-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run gemmini tests - command: .circleci/run-tests.sh gemmini + - run-tests: + tools-version: "esp-tools" + project-key: "gemmini" tracegen-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - tracegen-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run tracegen tests - command: .circleci/run-tests.sh tracegen + - run-tests: + project-key: "tracegen" tracegen-boom-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - tracegen-boom-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run tracegen-boom tests - command: .circleci/run-tests.sh tracegen-boom + - run-tests: + project-key: "tracegen-boom" firesim-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - firesim-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - extra-tests-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run FireSim tests - command: .circleci/run-firesim-tests.sh firesim + - run-tests: + extra-cache-restore: "extra-tests" + project-key: "firesim" + run-script: "run-firesim-tests.sh" fireboom-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.12 - environment: - JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit - TERM: dumb + executor: main-env steps: - - checkout - - run: - name: Create hash of toolchains - command: | - .circleci/create-hash.sh - - restore_cache: - keys: - - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - fireboom-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - extra-tests-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run FireSim tests - command: .circleci/run-firesim-tests.sh fireboom - no_output_timeout: 20m - + - run-tests: + extra-cache-restore: "extra-tests" + project-key: "fireboom" + run-script: "run-firesim-tests.sh" + timeout: "20m" # Order and dependencies of jobs to run workflows: From aae93ad065bb26d7f2209f973ee4f6e40827fb2d Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Thu, 6 Feb 2020 10:08:58 -0800 Subject: [PATCH 71/75] bump boom with rocc/lsu exu fix (#425) * bump boom with rocc/lsu exu fix --- generators/boom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/boom b/generators/boom index 1d4d0cda..779c62c5 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit 1d4d0cda50969a0c46f1807cc7b2201bbf42a6f3 +Subproject commit 779c62c5634847b517be64c554af66829de40067 From ccd6ecd41867ca11d262425a3606eeb5a31451bb Mon Sep 17 00:00:00 2001 From: Nathan Pemberton Date: Sun, 9 Feb 2020 17:58:56 -0800 Subject: [PATCH 72/75] Marhsal in chipyard (#415) * Move firemarshal into chipyard (was in firesim) --- .gitmodules | 3 +++ scripts/build-toolchains.sh | 2 +- scripts/init-submodules-no-riscv-tools.sh | 14 ++++++++++++-- sims/firesim | 2 +- software/firemarshal | 2 +- 5 files changed, 18 insertions(+), 5 deletions(-) mode change 120000 => 160000 software/firemarshal diff --git a/.gitmodules b/.gitmodules index d514a4e9..c4a9b2b9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -110,3 +110,6 @@ [submodule "generators/gemmini"] path = generators/gemmini url = https://github.com/ucb-bar/gemmini +[submodule "software/firemarshal"] + path = software/firemarshal + url = https://github.com/firesim/FireMarshal.git diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index d5d181e7..27c87417 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -141,5 +141,5 @@ cd "$RDIR" } > env-$TOOLCHAIN.sh # create general env.sh -ln -sf env-$TOOLCHAIN.sh env.sh +echo "source \$( realpath \$(dirname "\${BASH_SOURCE[0]}") )/env-$TOOLCHAIN.sh" >> env.sh echo "Toolchain Build Complete!" diff --git a/scripts/init-submodules-no-riscv-tools.sh b/scripts/init-submodules-no-riscv-tools.sh index 67e74e99..ef77374e 100755 --- a/scripts/init-submodules-no-riscv-tools.sh +++ b/scripts/init-submodules-no-riscv-tools.sh @@ -23,6 +23,7 @@ git config submodule.sims/firesim.update none git config submodule.vlsi/hammer-cadence-plugins.update none git config submodule.vlsi/hammer-synopsys-plugins.update none git config submodule.vlsi/hammer-mentor-plugins.update none +git config submodule.software/firemarshal.update none git submodule update --init --recursive #--jobs 8 # Un-ignore toolchain submodules @@ -37,6 +38,8 @@ git config --unset submodule.vlsi/hammer-synopsys-plugins.update git config --unset submodule.vlsi/hammer-mentor-plugins.update git config --unset submodule.generators/sha3.update +git config --unset submodule.software/firemarshal.update + # Non-recursive clone to exclude riscv-linux git submodule update --init generators/sha3 @@ -47,7 +50,14 @@ git submodule update --init sims/firesim cd sims/firesim # Initialize dependencies for MIDAS-level RTL simulation git submodule update --init sim/midas - # Exclude riscv-linux - git submodule update --init sw/firesim-software ) git config submodule.sims/firesim.update none + +# Only shallow clone needed for basic SW tests +git submodule update --init software/firemarshal + +# Configure firemarshal to know where our firesim installation is +if [ ! -f $RDIR/software/firemarshal/marshal-config.yaml ]; then + echo "firesim-dir: '../../sims/firesim/'" > $RDIR/software/firemarshal/marshal-config.yaml +fi +echo "PATH=\$( realpath \$(dirname "\${BASH_SOURCE[0]}") )/software/firemarshal:\$PATH" >> $RDIR/env.sh diff --git a/sims/firesim b/sims/firesim index b4951f25..c377a5f4 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit b4951f2589114e3849c77c798982afd10fc11b3e +Subproject commit c377a5f4a13f95c91a2d5e6ef6c1fc45f5041deb diff --git a/software/firemarshal b/software/firemarshal deleted file mode 120000 index c1e20e80..00000000 --- a/software/firemarshal +++ /dev/null @@ -1 +0,0 @@ -../sims/firesim/sw/firesim-software/ \ No newline at end of file diff --git a/software/firemarshal b/software/firemarshal new file mode 160000 index 00000000..ef2d467f --- /dev/null +++ b/software/firemarshal @@ -0,0 +1 @@ +Subproject commit ef2d467fe214d4d5294681ee8a3b25c3f470ea6b From cf9a52c052bcc7cec18193e57b3628f6ab738a9c Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Mon, 10 Feb 2020 02:14:32 +0000 Subject: [PATCH 73/75] bump firemarshal --- software/firemarshal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/firemarshal b/software/firemarshal index ef2d467f..c614142f 160000 --- a/software/firemarshal +++ b/software/firemarshal @@ -1 +1 @@ -Subproject commit ef2d467fe214d4d5294681ee8a3b25c3f470ea6b +Subproject commit c614142f85e29cfac93b251b761147a53d3a10ec From 7004bfdba35f23b86013e72bceda2486bd8bbabd Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Tue, 11 Feb 2020 00:55:05 +0000 Subject: [PATCH 74/75] bump to firemarshal dev --- software/firemarshal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/firemarshal b/software/firemarshal index c614142f..ef69bde3 160000 --- a/software/firemarshal +++ b/software/firemarshal @@ -1 +1 @@ -Subproject commit c614142f85e29cfac93b251b761147a53d3a10ec +Subproject commit ef69bde3b3fe7b233ac91e16aca3b955b6eff438 From 074add1d2c007951b0c96d617e39695aa0696416 Mon Sep 17 00:00:00 2001 From: Sagar Karandikar Date: Wed, 12 Feb 2020 22:36:02 +0000 Subject: [PATCH 75/75] bump to firesim with support for TracerV + Stack unwinding + Flame Graphs --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index c377a5f4..52aee63b 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit c377a5f4a13f95c91a2d5e6ef6c1fc45f5041deb +Subproject commit 52aee63bc04c3769695a41ba18319e316c2e78d5