From ed85e71c79c91466045023e28b2e479893337cde Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 21 Aug 2019 14:00:21 -0700 Subject: [PATCH 01/91] fix the way header files are handled by makefiles --- .circleci/defaults.sh | 2 +- common.mk | 2 +- generators/testchipip | 2 +- sims/verilator/Makefile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index cdccc3ba..439c4177 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -40,5 +40,5 @@ mapping["boomexample"]="SUB_PROJECT=example CONFIG=DefaultBoomConfig" mapping["boomrocketexample"]="SUB_PROJECT=example CONFIG=DefaultBoomAndRocketConfig" mapping["boom"]="SUB_PROJECT=example CONFIG=SmallBoomConfig" mapping["rocketchip"]="SUB_PROJECT=rocketchip" -mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=BlockDeviceModelRocketConfig TOP=BoomRocketTopWithBlockDevice" +mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=SimBlockDeviceRocketConfig TOP=BoomRocketTopWithBlockDevice" mapping["hwacha"]="SUB_PROJECT=example CONFIG=HwachaL2Config GENERATOR_PACKAGE=hwacha" diff --git a/common.mk b/common.mk index 3c333c68..16208e82 100644 --- a/common.mk +++ b/common.mk @@ -68,7 +68,7 @@ $(HARNESS_SMEMS_FILE) $(HARNESS_SMEMS_FIR): $(HARNESS_SMEMS_CONF) # remove duplicate files in blackbox/simfiles ######################################################################################## $(sim_common_files): $(sim_files) $(sim_top_blackboxes) $(sim_harness_blackboxes) - awk '{print $1;}' $^ | sort -u > $@ + awk '{print $1;}' $^ | sort -u | grep -v '.*\.h' > $@ ######################################################################################### # helper rule to just make verilog files diff --git a/generators/testchipip b/generators/testchipip index 85db33c3..63cd0a28 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 85db33c398c54eba6c979f798e975ad9a29020b4 +Subproject commit 63cd0a284e1ad905d9a5d369da4ac668b3455848 diff --git a/sims/verilator/Makefile b/sims/verilator/Makefile index 77514e20..31fc2d41 100644 --- a/sims/verilator/Makefile +++ b/sims/verilator/Makefile @@ -51,7 +51,7 @@ LDFLAGS := $(LDFLAGS) -L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib -L$(sim_dir) -lfesv VERILATOR_CC_OPTS = \ -O3 \ -CFLAGS "$(CXXFLAGS) -DTEST_HARNESS=V$(VLOG_MODEL) -DVERILATOR" \ - -CFLAGS "-I$(build_dir) -include $(build_dir)/$(long_name).plusArgs" \ + -CFLAGS "-I$(build_dir) -include $(build_dir)/$(long_name).plusArgs -include $(build_dir)/verilator.h" \ -LDFLAGS "$(LDFLAGS)" VERILATOR_NONCC_OPTS = \ From 72adc6981c995e2afd442def2674300b1ca3eb5b Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 21 Aug 2019 22:10:39 -0700 Subject: [PATCH 02/91] fix firesim test suite generation --- build.sbt | 5 ++- .../example/src/main/scala/Generator.scala | 1 + .../firechip/src/main/scala/Generator.scala | 38 ++----------------- .../src/main/scala/TargetConfigs.scala | 2 +- .../src/main/scala/TestSuites.scala | 2 +- 5 files changed, 10 insertions(+), 38 deletions(-) rename generators/{example => utilities}/src/main/scala/TestSuites.scala (99%) diff --git a/build.sbt b/build.sbt index c5562c45..d353a497 100644 --- a/build.sbt +++ b/build.sbt @@ -106,10 +106,11 @@ 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) + .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities) .settings(commonSettings) lazy val utilities = conditionalDependsOn(project in file("generators/utilities")) + .dependsOn(rocketchip, boom) .settings(commonSettings) lazy val icenet = (project in file("generators/icenet")) @@ -165,7 +166,7 @@ lazy val midas = ProjectRef(firesimDir, "midas") lazy val firesimLib = ProjectRef(firesimDir, "firesimLib") lazy val firechip = (project in file("generators/firechip")) - .dependsOn(boom, icenet, testchipip, sifive_blocks, sifive_cache, midasTargetUtils, midas, firesimLib % "test->test;compile->compile") + .dependsOn(boom, icenet, testchipip, sifive_blocks, sifive_cache, utilities, midasTargetUtils, midas, firesimLib % "test->test;compile->compile") .settings( commonSettings, testGrouping in Test := isolateAllTests( (definedTests in Test).value ) diff --git a/generators/example/src/main/scala/Generator.scala b/generators/example/src/main/scala/Generator.scala index 34f16e4e..f164b481 100644 --- a/generators/example/src/main/scala/Generator.scala +++ b/generators/example/src/main/scala/Generator.scala @@ -4,6 +4,7 @@ import chisel3._ import freechips.rocketchip.config.{Parameters} import freechips.rocketchip.util.{GeneratorApp} +import utilities.TestSuiteHelper object Generator extends GeneratorApp { // add unique test suites diff --git a/generators/firechip/src/main/scala/Generator.scala b/generators/firechip/src/main/scala/Generator.scala index 06febd3a..0dd0e1eb 100644 --- a/generators/firechip/src/main/scala/Generator.scala +++ b/generators/firechip/src/main/scala/Generator.scala @@ -16,10 +16,10 @@ import freechips.rocketchip.config.Parameters import freechips.rocketchip.subsystem.RocketTilesKey import freechips.rocketchip.tile.XLen -import boom.system.{BoomTilesKey, BoomTestSuites} - import firesim.util.{GeneratorArgs, HasTargetAgnosticUtilites, HasFireSimGeneratorUtilities} +import utilities.TestSuiteHelper + trait HasTestSuites { val rv64RegrTestNames = collection.mutable.LinkedHashSet( "rv64ud-v-fcvt", @@ -58,38 +58,8 @@ trait HasTestSuites { "rv32ui-p-sll") def addTestSuites(targetName: String, params: Parameters) { - val coreParams = - if (params(RocketTilesKey).nonEmpty) { - params(RocketTilesKey).head.core - } else { - params(BoomTilesKey).head.core - } - val xlen = params(XLen) - val vm = coreParams.useVM - val env = if (vm) List("p","v") else List("p") - coreParams.fpu foreach { case cfg => - if (xlen == 32) { - TestGeneration.addSuites(env.map(rv32uf)) - if (cfg.fLen >= 64) - TestGeneration.addSuites(env.map(rv32ud)) - } else { - TestGeneration.addSuite(rv32udBenchmarks) - TestGeneration.addSuites(env.map(rv64uf)) - if (cfg.fLen >= 64) - TestGeneration.addSuites(env.map(rv64ud)) - } - } - if (coreParams.useAtomics) TestGeneration.addSuites(env.map(if (xlen == 64) rv64ua else rv32ua)) - if (coreParams.useCompressed) TestGeneration.addSuites(env.map(if (xlen == 64) rv64uc else rv32uc)) - val (rvi, rvu) = - if (params(BoomTilesKey).nonEmpty) ((if (vm) BoomTestSuites.rv64i else BoomTestSuites.rv64pi), rv64u) - else if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u) - else ((if (vm) rv32i else rv32pi), rv32u) - - TestGeneration.addSuites(rvi.map(_("p"))) - TestGeneration.addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env)))) - TestGeneration.addSuite(benchmarks) - TestGeneration.addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames)) + TestSuiteHelper.addRocketTestSuites(params) + TestSuiteHelper.addBoomTestSuites(params) TestGeneration.addSuite(FastBlockdevTests) TestGeneration.addSuite(SlowBlockdevTests) if (!targetName.contains("NoNIC")) diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 9be95d89..c81fe843 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -137,7 +137,7 @@ class FireSimBoomConfig extends Config( new WithBoomL2TLBs(1024) ++ new WithoutClockGating ++ // Using a small config because it has 64-bit system bus, and compiles quickly - new boom.system.SmallBoomConfig) + new boom.common.SmallBoomConfig) // A safer implementation than the one in BOOM in that it // duplicates whatever BOOMTileKey.head is present N times. This prevents diff --git a/generators/example/src/main/scala/TestSuites.scala b/generators/utilities/src/main/scala/TestSuites.scala similarity index 99% rename from generators/example/src/main/scala/TestSuites.scala rename to generators/utilities/src/main/scala/TestSuites.scala index 11425bdb..ab0ff8d5 100644 --- a/generators/example/src/main/scala/TestSuites.scala +++ b/generators/utilities/src/main/scala/TestSuites.scala @@ -1,4 +1,4 @@ -package example +package utilities import scala.collection.mutable.{LinkedHashSet} From b09794f548b44656a3dcab903317fa1a000e2398 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 21 Aug 2019 16:50:36 -0700 Subject: [PATCH 03/91] make BlockDevice, SerialAdapter, and IceNIC connect to fbus/pbus instead of sbus --- generators/icenet | 2 +- generators/testchipip | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generators/icenet b/generators/icenet index bba264d6..baa40ed8 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit bba264d68d366180f6f9b55061ee9408425d8229 +Subproject commit baa40ed85d7425ef5ce206d52fb8b2759c6f6827 diff --git a/generators/testchipip b/generators/testchipip index 63cd0a28..aa13f6cc 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 63cd0a284e1ad905d9a5d369da4ac668b3455848 +Subproject commit aa13f6ccc1a05a20e52a1600b6c8c796d306f1cd From a494f88af0acb161a3523ff8597ed914e2a47218 Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Sun, 25 Aug 2019 08:22:41 -0700 Subject: [PATCH 04/91] Add sha3 repo and config, bump tools for xcustom fix --- .gitmodules | 3 +++ build.sbt | 6 +++++- generators/example/src/main/scala/Configs.scala | 4 ++++ generators/rocc-template | 1 + toolchains/esp-tools | 2 +- 5 files changed, 14 insertions(+), 2 deletions(-) create mode 160000 generators/rocc-template diff --git a/.gitmodules b/.gitmodules index 26846989..fc31b672 100644 --- a/.gitmodules +++ b/.gitmodules @@ -55,3 +55,6 @@ [submodule "tools/treadle"] path = tools/treadle url = https://github.com/freechipsproject/treadle.git +[submodule "generators/rocc-template"] + path = generators/rocc-template + url = https://github.com/ucb-bar/rocc-template.git diff --git a/build.sbt b/build.sbt index c5562c45..9f33da3d 100644 --- a/build.sbt +++ b/build.sbt @@ -106,7 +106,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) + .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, rocc_template) .settings(commonSettings) lazy val utilities = conditionalDependsOn(project in file("generators/utilities")) @@ -124,6 +124,10 @@ lazy val boom = (project in file("generators/boom")) .dependsOn(rocketchip) .settings(commonSettings) +lazy val rocc_template = (project in file("generators/rocc-template")) + .dependsOn(rocketchip, `chisel-testers`) + .settings(commonSettings) + lazy val tapeout = conditionalDependsOn(project in file("./tools/barstools/tapeout/")) .settings(commonSettings) diff --git a/generators/example/src/main/scala/Configs.scala b/generators/example/src/main/scala/Configs.scala index c7e70dd2..098b4e16 100644 --- a/generators/example/src/main/scala/Configs.scala +++ b/generators/example/src/main/scala/Configs.scala @@ -27,6 +27,10 @@ class RoccRocketConfig extends Config( new WithRoccExample ++ new DefaultRocketConfig) +class Sha3RocketConfig extends Config( + new sha3.WithSha3Accel ++ + new DefaultRocketConfig) + class PWMRocketConfig extends Config( new WithPWMBoomRocketTop ++ new BaseRocketConfig) diff --git a/generators/rocc-template b/generators/rocc-template new file mode 160000 index 00000000..fa165f8a --- /dev/null +++ b/generators/rocc-template @@ -0,0 +1 @@ +Subproject commit fa165f8a54c492cacd794964120b56d48d2fe7b2 diff --git a/toolchains/esp-tools b/toolchains/esp-tools index aba7bd82..f13ae53f 160000 --- a/toolchains/esp-tools +++ b/toolchains/esp-tools @@ -1 +1 @@ -Subproject commit aba7bd828d4fd1c5fc3ac227524ccfd350410ade +Subproject commit f13ae53fcd09c1119a1697df37335718904fc7be From b0743538f31f34667c39c45b6771913c3e38566b Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Sun, 25 Aug 2019 09:00:42 -0700 Subject: [PATCH 05/91] bump rocc-template for chisel fixes --- generators/rocc-template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/rocc-template b/generators/rocc-template index fa165f8a..3e4f9fa7 160000 --- a/generators/rocc-template +++ b/generators/rocc-template @@ -1 +1 @@ -Subproject commit fa165f8a54c492cacd794964120b56d48d2fe7b2 +Subproject commit 3e4f9fa768f4524edc01439a3453f985325f45c6 From 36b25bbd09dbc2eb73973118160e8f25f6123a99 Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Sun, 25 Aug 2019 09:09:03 -0700 Subject: [PATCH 06/91] bump rocc-template so it builds again --- generators/rocc-template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/rocc-template b/generators/rocc-template index 3e4f9fa7..4882648c 160000 --- a/generators/rocc-template +++ b/generators/rocc-template @@ -1 +1 @@ -Subproject commit 3e4f9fa768f4524edc01439a3453f985325f45c6 +Subproject commit 4882648c653df0dc6d365d5a5c677c13952541aa From 208a27da7948fbf33236c90225f772a9585fe30b Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Mon, 26 Aug 2019 10:43:43 -0700 Subject: [PATCH 07/91] bump sha3 and tools for xs setup --- generators/rocc-template | 2 +- toolchains/esp-tools | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generators/rocc-template b/generators/rocc-template index 4882648c..83dd1955 160000 --- a/generators/rocc-template +++ b/generators/rocc-template @@ -1 +1 @@ -Subproject commit 4882648c653df0dc6d365d5a5c677c13952541aa +Subproject commit 83dd1955a9a6f277addfbcc65394986e73fc03b2 diff --git a/toolchains/esp-tools b/toolchains/esp-tools index f13ae53f..dcb6012f 160000 --- a/toolchains/esp-tools +++ b/toolchains/esp-tools @@ -1 +1 @@ -Subproject commit f13ae53fcd09c1119a1697df37335718904fc7be +Subproject commit dcb6012f77101e793948cc90ac31b3735a9f3f6d From 8d9b3ddfb2c80e1914e956b43d40fa0733966832 Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Mon, 26 Aug 2019 12:36:50 -0700 Subject: [PATCH 08/91] Change spaces to underscores in sim_out_name This fixes #209 --- variables.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.mk b/variables.mk index ca0f8fc9..41d5ef81 100644 --- a/variables.mk +++ b/variables.mk @@ -143,7 +143,7 @@ output_dir=$(sim_dir)/output/$(long_name) BINARY ?= SIM_FLAGS ?= VERBOSE_FLAGS ?= +verbose -sim_out_name = $(notdir $(basename $(BINARY))).$(long_name) +sim_out_name = $(subst $() $(),_,$(notdir $(basename $(BINARY))).$(long_name)) ######################################################################################### # build output directory for compilation From 950aee07491f44bf0c61dcbf8d22f69530eb3ed4 Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Mon, 26 Aug 2019 12:36:50 -0700 Subject: [PATCH 09/91] Change spaces to underscores in sim_out_name This fixes #209 --- variables.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.mk b/variables.mk index ca0f8fc9..41d5ef81 100644 --- a/variables.mk +++ b/variables.mk @@ -143,7 +143,7 @@ output_dir=$(sim_dir)/output/$(long_name) BINARY ?= SIM_FLAGS ?= VERBOSE_FLAGS ?= +verbose -sim_out_name = $(notdir $(basename $(BINARY))).$(long_name) +sim_out_name = $(subst $() $(),_,$(notdir $(basename $(BINARY))).$(long_name)) ######################################################################################### # build output directory for compilation From e7c727372ff3cb9ccf91a8ea3575fb2b4e040c70 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 26 Aug 2019 14:32:08 -0700 Subject: [PATCH 10/91] Cleanup configs --- generators/boom | 2 +- .../example/src/main/scala/BoomConfigs.scala | 101 +++--- .../example/src/main/scala/ConfigMixins.scala | 44 +-- .../example/src/main/scala/Configs.scala | 300 ++++-------------- .../src/main/scala/HeteroConfigs.scala | 84 +++++ .../example/src/main/scala/Subsystem.scala | 108 +++++++ .../example/src/main/scala/System.scala | 63 ++++ .../example/src/main/scala/TestHarness.scala | 8 +- generators/example/src/main/scala/Top.scala | 40 +-- .../utilities/src/main/scala/TestSuites.scala | 2 +- variables.mk | 4 +- 11 files changed, 412 insertions(+), 344 deletions(-) create mode 100644 generators/example/src/main/scala/HeteroConfigs.scala create mode 100644 generators/example/src/main/scala/Subsystem.scala create mode 100644 generators/example/src/main/scala/System.scala diff --git a/generators/boom b/generators/boom index 4e9d496d..793912ee 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit 4e9d496d3678cc5ae005669a448ae9e89f8ae847 +Subproject commit 793912eef8a9f09c13bd791c33ba682350a6026a diff --git a/generators/example/src/main/scala/BoomConfigs.scala b/generators/example/src/main/scala/BoomConfigs.scala index f328b902..c97154aa 100644 --- a/generators/example/src/main/scala/BoomConfigs.scala +++ b/generators/example/src/main/scala/BoomConfigs.scala @@ -3,88 +3,65 @@ package example import chisel3._ import freechips.rocketchip.config.{Config} -import freechips.rocketchip.subsystem.{WithJtagDTM} - -import boom.common._ // --------------------- // BOOM Configs // --------------------- class SmallBoomConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.SmallBoomConfig) + new WithTop ++ // use normal top + new WithBootROM ++ // use testchipip bootrom + 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 WithNormalBoomRocketTop ++ + new WithTop ++ new WithBootROM ++ - new boom.common.MediumBoomConfig) + 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 WithNormalBoomRocketTop ++ + new WithTop ++ new WithBootROM ++ - new boom.common.LargeBoomConfig) + 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 WithNormalBoomRocketTop ++ + new WithTop ++ new WithBootROM ++ - new boom.common.MegaBoomConfig) + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithMegaBooms ++ // 4-wide BOOM + new boom.common.WithNBoomCores(1) ++ + new freechips.rocketchip.system.BaseConfig) -class jtagSmallBoomConfig extends Config( - new WithDTMBoomRocketTop ++ +class DualSmallBoomConfig extends Config( + new WithTop ++ new WithBootROM ++ - new WithJtagDTM ++ - new boom.common.SmallBoomConfig) - -class jtagMediumBoomConfig extends Config( - new WithDTMBoomRocketTop ++ - new WithBootROM ++ - new WithJtagDTM ++ - new boom.common.MediumBoomConfig) - -class jtagLargeBoomConfig extends Config( - new WithDTMBoomRocketTop ++ - new WithBootROM ++ - new WithJtagDTM ++ - new boom.common.LargeBoomConfig) - -class jtagMegaBoomConfig extends Config( - new WithDTMBoomRocketTop ++ - new WithBootROM ++ - new WithJtagDTM ++ - new boom.common.MegaBoomConfig) - -class SmallDualBoomConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.SmallDualBoomConfig) + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithSmallBooms ++ + new boom.common.WithNBoomCores(2) ++ // dual-core + new freechips.rocketchip.system.BaseConfig) class TracedSmallBoomConfig extends Config( - new WithNormalBoomRocketTop ++ + new WithTop ++ new WithBootROM ++ - new boom.common.TracedSmallBoomConfig) + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithTrace ++ // enable trace port on BOOM + new boom.common.WithSmallBooms ++ + new boom.common.WithNBoomCores(1) ++ + new freechips.rocketchip.system.BaseConfig) class SmallRV32UnifiedBoomConfig extends Config( - new WithNormalBoomRocketTop ++ + new WithTop ++ new WithBootROM ++ - new boom.common.SmallRV32UnifiedBoomConfig) - -// -------------------------- -// BOOM + Rocket Configs -// -------------------------- - -class SmallBoomAndRocketConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.SmallBoomAndRocketConfig) - -class MediumBoomAndRocketConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.MediumBoomAndRocketConfig) - -class DualMediumBoomAndDualRocketConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.DualMediumBoomAndDualRocketConfig) + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithUnifiedMemIntIQs ++ // use unified mem+int issue queues + new boom.common.WithSmallBooms ++ + 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 17fac94d..17cbcaa5 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -9,7 +9,7 @@ import freechips.rocketchip.diplomacy.{LazyModule, ValName} import freechips.rocketchip.devices.tilelink.BootROMParams import freechips.rocketchip.tile.{XLen, BuildRoCC, TileKey, LazyRoCC} -import boom.system.{BoomTilesKey} +import boom.common.{BoomTilesKey} import testchipip._ @@ -52,43 +52,43 @@ class WithGPIO extends Config((site, here, up) => { /** * Class to specify a "plain" top level BOOM and/or Rocket system */ -class WithNormalBoomRocketTop extends Config((site, here, up) => { - case BuildBoomRocketTop => (clock: Clock, reset: Bool, p: Parameters) => { - Module(LazyModule(new BoomRocketTop()(p)).module) +class WithTop extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { + Module(LazyModule(new Top()(p)).module) } }) /** * Class to specify a top level BOOM and/or Rocket system with DTM */ -class WithDTMBoomRocketTop extends Config((site, here, up) => { - case BuildBoomRocketTopWithDTM => (clock: Clock, reset: Bool, p: Parameters) => { - Module(LazyModule(new BoomRocketTopWithDTM()(p)).module) +class WithDTMTop extends Config((site, here, up) => { + case BuildTopWithDTM => (clock: Clock, reset: Bool, p: Parameters) => { + Module(LazyModule(new TopWithDTM()(p)).module) } }) /** * Class to specify a top level BOOM and/or Rocket system with PWM */ -class WithPWMBoomRocketTop extends Config((site, here, up) => { - case BuildBoomRocketTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new BoomRocketTopWithPWMTL()(p)).module) +class WithPWMTop extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => + Module(LazyModule(new TopWithPWMTL()(p)).module) }) /** * Class to specify a top level BOOM and/or Rocket system with a PWM AXI4 */ -class WithPWMAXI4BoomRocketTop extends Config((site, here, up) => { - case BuildBoomRocketTop => (clock: Clock, reset: Bool, p: Parameters) => - Module(LazyModule(new BoomRocketTopWithPWMAXI4()(p)).module) +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 block device */ -class WithBlockDeviceModelBoomRocketTop extends Config((site, here, up) => { - case BuildBoomRocketTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new BoomRocketTopWithBlockDevice()(p)).module) +class WithBlockDeviceModelTop extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { + val top = Module(LazyModule(new TopWithBlockDevice()(p)).module) top.connectBlockDeviceModel() top } @@ -97,9 +97,9 @@ class WithBlockDeviceModelBoomRocketTop extends Config((site, here, up) => { /** * Class to specify a top level BOOM and/or Rocket system with a simulator block device */ -class WithSimBlockDeviceBoomRocketTop extends Config((site, here, up) => { - case BuildBoomRocketTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new BoomRocketTopWithBlockDevice()(p)).module) +class WithSimBlockDeviceTop extends Config((site, here, up) => { + case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { + val top = Module(LazyModule(new TopWithBlockDevice()(p)).module) top.connectSimBlockDevice(clock, reset) top } @@ -108,9 +108,9 @@ class WithSimBlockDeviceBoomRocketTop extends Config((site, here, up) => { /** * Class to specify a top level BOOM and/or Rocket system with GPIO */ -class WithGPIOBoomRocketTop extends Config((site, here, up) => { - case BuildBoomRocketTop => (clock: Clock, reset: Bool, p: Parameters) => { - val top = Module(LazyModule(new BoomRocketTopWithGPIO()(p)).module) +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 diff --git a/generators/example/src/main/scala/Configs.scala b/generators/example/src/main/scala/Configs.scala index c7e70dd2..5004e6ee 100644 --- a/generators/example/src/main/scala/Configs.scala +++ b/generators/example/src/main/scala/Configs.scala @@ -3,264 +3,100 @@ package example import chisel3._ import freechips.rocketchip.config.{Config} -import freechips.rocketchip.subsystem.{WithRoccExample, WithNMemoryChannels, WithNBigCores, WithRV32, WithExtMemSize, WithNBanks, WithInclusiveCache} - -import testchipip._ // -------------- // Rocket Configs // -------------- -class BaseRocketConfig extends Config( +class RocketConfig extends Config( + new WithTop ++ // use default top + new WithBootROM ++ // use default bootrom + 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 (implicitly creates Rocket cores) + +class HwachaRocketConfig extends Config( + new WithTop ++ new WithBootROM ++ - new freechips.rocketchip.system.DefaultConfig) - -class DefaultRocketConfig extends Config( - new WithNormalBoomRocketTop ++ - new BaseRocketConfig) - -class HwachaConfig extends Config( - new hwacha.DefaultHwachaConfig ++ - new DefaultRocketConfig) + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) class RoccRocketConfig extends Config( - new WithRoccExample ++ - new DefaultRocketConfig) + new WithTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithRoccExample ++ // use example RoCC-based accelerator + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) + +class jtagRocketConfig extends Config( + new WithDTMTop ++ // use top with dtm + new freechips.rocketchip.subsystem.WithJtagDTM ++ // add jtag/DTM module to coreplex + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) class PWMRocketConfig extends Config( - new WithPWMBoomRocketTop ++ - new BaseRocketConfig) + new WithPWMTop ++ // use top with tilelink-controlled PWM + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) -class PWMAXI4RocketConfig extends Config( - new WithPWMAXI4BoomRocketTop ++ - new BaseRocketConfig) +class PWMRAXI4ocketConfig extends Config( + new WithPWMAXI4Top ++ // use top with axi4-controlled PWM + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) class SimBlockDeviceRocketConfig extends Config( - new WithBlockDevice ++ - new WithSimBlockDeviceBoomRocketTop ++ - new BaseRocketConfig) + new testchipip.WithBlockDevice ++ // add block-device module to peripherybus + new WithSimBlockDeviceTop ++ // use top with block-device IOs and connect to simblockdevice + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) class BlockDeviceModelRocketConfig extends Config( - new WithBlockDevice ++ - new WithBlockDeviceModelBoomRocketTop ++ - new BaseRocketConfig) + 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 freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) class GPIORocketConfig extends Config( - new WithGPIO ++ - new WithGPIOBoomRocketTop ++ - new BaseRocketConfig) + new WithGPIO ++ // add GPIOs to the peripherybus + new WithGPIOTop ++ // use top with GPIOs + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) class DualCoreRocketConfig extends Config( - new WithNBigCores(2) ++ - new DefaultRocketConfig) + new WithTop ++ + new WithBootROM ++ + 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 WithRV32 ++ - new DefaultRocketConfig) - -class GB1MemoryConfig extends Config( - new WithExtMemSize((1<<30) * 1L) ++ - new DefaultRocketConfig) - -class RocketL2Config extends Config( - new WithInclusiveCache ++ - new DefaultRocketConfig) - -class HwachaL2Config extends Config( - new hwacha.DefaultHwachaConfig ++ - new WithInclusiveCache ++ - new DefaultRocketConfig) - -// ------------ -// BOOM Configs -// ------------ - -class BaseBoomConfig extends Config( + new WithTop ++ new WithBootROM ++ - new boom.common.LargeBoomConfig) - -class SmallBaseBoomConfig extends Config( - new WithBootROM ++ - new boom.common.SmallBoomConfig) - -class DefaultBoomConfig extends Config( - new WithNormalBoomRocketTop ++ - new BaseBoomConfig) - -class SmallDefaultBoomConfig extends Config( - new WithNormalBoomRocketTop ++ - new SmallBaseBoomConfig) - -class HwachaBoomConfig extends Config( - new hwacha.DefaultHwachaConfig ++ - new DefaultBoomConfig) - -class RoccBoomConfig extends Config( - new WithRoccExample ++ - new DefaultBoomConfig) - -class PWMBoomConfig extends Config( - new WithPWMBoomRocketTop ++ - new BaseBoomConfig) - -class PWMAXI4BoomConfig extends Config( - new WithPWMAXI4BoomRocketTop ++ - new BaseBoomConfig) - -class SimBlockDeviceBoomConfig extends Config( - new WithBlockDevice ++ - new WithSimBlockDeviceBoomRocketTop ++ - new BaseBoomConfig) - -class BlockDeviceModelBoomConfig extends Config( - new WithBlockDevice ++ - new WithBlockDeviceModelBoomRocketTop ++ - new BaseBoomConfig) - -class GPIOBoomConfig extends Config( - new WithGPIO ++ - new WithGPIOBoomRocketTop ++ - new BaseBoomConfig) - -/** - * Slightly different looking configs since we need to override - * the `WithNBoomCores` with the DefaultBoomConfig params - */ -class DualCoreBoomConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.WithRVC ++ - new boom.common.WithLargeBooms ++ - new boom.common.BaseBoomConfig ++ - new boom.common.WithNBoomCores(2) ++ - new freechips.rocketchip.subsystem.WithoutTLMonitors ++ - new freechips.rocketchip.system.BaseConfig) - -class DualCoreSmallBoomConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.WithRVC ++ - new boom.common.WithSmallBooms ++ - new boom.common.BaseBoomConfig ++ - new boom.common.WithNBoomCores(2) ++ - new freechips.rocketchip.subsystem.WithoutTLMonitors ++ - new freechips.rocketchip.system.BaseConfig) - -class RV32UnifiedBoomConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.SmallRV32UnifiedBoomConfig) - -class BoomL2Config extends Config( - new WithInclusiveCache ++ - new SmallDefaultBoomConfig) - -// --------------------- -// BOOM and Rocket Configs -// --------------------- - -class BaseBoomAndRocketConfig extends Config( - new WithBootROM ++ - new boom.common.WithRenumberHarts ++ - new boom.common.WithRVC ++ - new boom.common.WithLargeBooms ++ - new boom.common.BaseBoomConfig ++ - new boom.common.WithNBoomCores(1) ++ - new freechips.rocketchip.subsystem.WithoutTLMonitors ++ + 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 SmallBaseBoomAndRocketConfig extends Config( +class GB1MemoryRocketConfig extends Config( + new WithTop ++ new WithBootROM ++ - new boom.common.WithRenumberHarts ++ - new boom.common.WithRVC ++ - new boom.common.WithSmallBooms ++ - new boom.common.BaseBoomConfig ++ - new boom.common.WithNBoomCores(1) ++ - new freechips.rocketchip.subsystem.WithoutTLMonitors ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithExtMemSize((1<<30) * 1L) ++ // use 2GB simulated external memory new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) -class DefaultBoomAndRocketConfig extends Config( - new WithNormalBoomRocketTop ++ - new BaseBoomAndRocketConfig) - -class SmallDefaultBoomAndRocketConfig extends Config( - new WithNormalBoomRocketTop ++ - new SmallBaseBoomAndRocketConfig) - -class HwachaBoomAndRocketConfig extends Config( - new hwacha.DefaultHwachaConfig ++ - new DefaultBoomAndRocketConfig) - -class RoccBoomAndRocketConfig extends Config( - new WithRoccExample ++ - new DefaultBoomAndRocketConfig) - -class PWMBoomAndRocketConfig extends Config( - new WithPWMBoomRocketTop ++ - new BaseBoomAndRocketConfig) - -class PWMAXI4BoomAndRocketConfig extends Config( - new WithPWMAXI4BoomRocketTop ++ - new BaseBoomAndRocketConfig) - -class SimBlockDeviceBoomAndRocketConfig extends Config( - new WithBlockDevice ++ - new WithSimBlockDeviceBoomRocketTop ++ - new BaseBoomAndRocketConfig) - -class BlockDeviceModelBoomAndRocketConfig extends Config( - new WithBlockDevice ++ - new WithBlockDeviceModelBoomRocketTop ++ - new BaseBoomAndRocketConfig) - -class GPIOBoomAndRocketConfig extends Config( - new WithGPIO ++ - new WithGPIOBoomRocketTop ++ - new BaseBoomAndRocketConfig) - -class DualCoreBoomAndOneRocketConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.WithRenumberHarts ++ - new boom.common.WithRVC ++ - new boom.common.WithLargeBooms ++ - new boom.common.BaseBoomConfig ++ - new boom.common.WithNBoomCores(2) ++ - new freechips.rocketchip.subsystem.WithoutTLMonitors ++ - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.system.BaseConfig) - -class DualBoomAndOneHwachaRocketConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new WithMultiRoCC ++ - new WithMultiRoCCHwacha(0) ++ // put Hwacha just on hart0 which was renumbered to Rocket - new boom.common.WithRenumberHarts(rocketFirst = true) ++ - new hwacha.DefaultHwachaConfig ++ - new boom.common.WithRVC ++ - new boom.common.WithLargeBooms ++ - new boom.common.BaseBoomConfig ++ - new boom.common.WithNBoomCores(2) ++ - new freechips.rocketchip.subsystem.WithoutTLMonitors ++ - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.system.BaseConfig) - -class RV32BoomAndRocketConfig extends Config( - new WithNormalBoomRocketTop ++ - new WithBootROM ++ - new boom.common.WithRenumberHarts ++ - new boom.common.WithBoomRV32 ++ - new boom.common.WithRVC ++ - new boom.common.WithLargeBooms ++ - new boom.common.BaseBoomConfig ++ - new boom.common.WithNBoomCores(1) ++ - new freechips.rocketchip.subsystem.WithoutTLMonitors ++ - new freechips.rocketchip.subsystem.WithRV32 ++ - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.system.BaseConfig) - -class DualCoreRocketL2Config extends Config( - new WithInclusiveCache ++ - new DualCoreRocketConfig) diff --git a/generators/example/src/main/scala/HeteroConfigs.scala b/generators/example/src/main/scala/HeteroConfigs.scala new file mode 100644 index 00000000..898991d7 --- /dev/null +++ b/generators/example/src/main/scala/HeteroConfigs.scala @@ -0,0 +1,84 @@ +package example + +import chisel3._ + +import freechips.rocketchip.config.{Config} + +// --------------------- +// Heterogenous Configs +// --------------------- + +class LargeBoomAndRocketConfig extends Config( + new WithTop ++ // default top + new WithBootROM ++ // default bootrom + new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive l2 + new boom.common.WithRenumberHarts ++ // avoid hartid overlap + new boom.common.WithLargeBooms ++ // 3-wide boom + new boom.common.WithNBoomCores(1) ++ // single-core boom + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single-core rocket + new freechips.rocketchip.system.BaseConfig) // "Base" rocketchip system + +class HwachaLargeBoomAndHwachaRocketConfig extends Config( + new WithTop ++ + new WithBootROM ++ + new hwacha.DefaultHwachaConfig ++ // add hwacha to all harts + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithRenumberHarts ++ + new boom.common.WithLargeBooms ++ + new boom.common.WithNBoomCores(1) ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) + +class RoccLargeBoomAndRoccRocketConfig extends Config( + new WithTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithRoccExample ++ // add example rocc accelerator to all harts + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithRenumberHarts ++ + new boom.common.WithLargeBooms ++ + new boom.common.WithNBoomCores(1) ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) + +class DualLargeBoomAndRocketConfig extends Config( + new WithTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithRenumberHarts ++ + new boom.common.WithLargeBooms ++ + new boom.common.WithNBoomCores(2) ++ // 2-boom cores + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) + +class DualLargeBoomAndHwachaRocketConfig extends Config( + new WithTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new WithMultiRoCC ++ // support heterogeneous rocc + new WithMultiRoCCHwacha(2) ++ // put hwacha on hart-2 (rocket) + new boom.common.WithRenumberHarts ++ + new boom.common.WithLargeBooms ++ + new boom.common.WithNBoomCores(2) ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) + +class LargeBoomAndRV32RocketConfig extends Config( + new WithTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithRenumberHarts ++ + new boom.common.WithLargeBooms ++ + new boom.common.WithNBoomCores(1) ++ + new freechips.rocketchip.subsystem.WithRV32 ++ // use 32-bit rocket + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) + +class DualLargeBoomAndDualRocketConfig extends Config( + new WithTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithRenumberHarts ++ + new boom.common.WithLargeBooms ++ + new boom.common.WithNBoomCores(2) ++ // 2 boom cores + new freechips.rocketchip.subsystem.WithNBigCores(2) ++ // 2 rocket cores + new freechips.rocketchip.system.BaseConfig) diff --git a/generators/example/src/main/scala/Subsystem.scala b/generators/example/src/main/scala/Subsystem.scala new file mode 100644 index 00000000..7888bc4f --- /dev/null +++ b/generators/example/src/main/scala/Subsystem.scala @@ -0,0 +1,108 @@ +//****************************************************************************** +// Copyright (c) 2019 - 2019, The Regents of the University of California (Regents). +// All Rights Reserved. See LICENSE and LICENSE.SiFive for license details. +//------------------------------------------------------------------------------ + +package example + +import chisel3._ +import chisel3.internal.sourceinfo.{SourceInfo} + +import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.diplomaticobjectmodel.model.{OMInterrupt} +import freechips.rocketchip.diplomaticobjectmodel.logicaltree.{RocketTileLogicalTreeNode, LogicalModuleTree} +import freechips.rocketchip.tile._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.util._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.amba.axi4._ + +import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey} + + +trait HasBoomAndRocketTiles extends HasTiles + with CanHavePeripheryPLIC + with CanHavePeripheryCLINT + with HasPeripheryDebug +{ this: BaseSubsystem => + + val module: HasBoomAndRocketTilesModuleImp + + protected val rocketTileParams = p(RocketTilesKey) + protected val boomTileParams = p(BoomTilesKey) + // crossing can either be per tile or global (aka only 1 crossing specified) + private val rocketCrossings = perTileOrGlobalSetting(p(RocketCrossingKey), rocketTileParams.size) + private val boomCrossings = perTileOrGlobalSetting(p(BoomCrossingKey), boomTileParams.size) + + // Make a tile and wire its nodes into the system, + // according to the specified type of clock crossing. + // Note that we also inject new nodes into the tile itself, + // also based on the crossing type. + val rocketTiles = rocketTileParams.zip(rocketCrossings).map { case (tp, crossing) => + val rocket = LazyModule(new RocketTile(tp, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) + + connectMasterPortsToSBus(rocket, crossing) + connectSlavePortsToCBus(rocket, crossing) + + def treeNode: RocketTileLogicalTreeNode = new RocketTileLogicalTreeNode(rocket.rocketLogicalTree.getOMInterruptTargets) + LogicalModuleTree.add(logicalTreeNode, rocket.rocketLogicalTree) + + rocket + } + + val boomTiles = boomTileParams.zip(boomCrossings).map { case (tp, crossing) => + val boom = LazyModule(new BoomTile(tp, crossing, PriorityMuxHartIdFromSeq(boomTileParams), logicalTreeNode)) + + connectMasterPortsToSBus(boom, crossing) + connectSlavePortsToCBus(boom, crossing) + + def treeNode: RocketTileLogicalTreeNode = new RocketTileLogicalTreeNode(boom.rocketLogicalTree.getOMInterruptTargets) + LogicalModuleTree.add(logicalTreeNode, boom.rocketLogicalTree) + + boom + } + + // combine tiles and connect interrupts based on the order of harts + val boomAndRocketTiles = (rocketTiles ++ boomTiles).sortWith(_.tileParams.hartId < _.tileParams.hartId).map { + tile => { + connectInterrupts(tile, Some(debug), clintOpt, plicOpt) + + tile + } + } + + def coreMonitorBundles = (rocketTiles map { t => t.module.core.rocketImpl.coreMonitorBundle}).toList ++ + (boomTiles map { t => t.module.core.coreMonitorBundle}).toList +} + +trait HasBoomAndRocketTilesModuleImp extends HasTilesModuleImp + with HasPeripheryDebugModuleImp +{ + val outer: HasBoomAndRocketTiles +} + +class Subsystem(implicit p: Parameters) extends BaseSubsystem + with HasBoomAndRocketTiles +{ + val tiles = boomAndRocketTiles + override lazy val module = new SubsystemModuleImp(this) + + def getOMInterruptDevice(resourceBindingsMap: ResourceBindingsMap): Seq[OMInterrupt] = Nil +} + +class SubsystemModuleImp[+L <: Subsystem](_outer: L) extends BaseSubsystemModuleImp(_outer) + with HasResetVectorWire + with HasBoomAndRocketTilesModuleImp +{ + tile_inputs.zip(outer.hartIdList).foreach { case(wire, i) => + wire.hartid := i.U + wire.reset_vector := global_reset_vector + } + + // create file with boom params + ElaborationArtefacts.add("""core.config""", outer.tiles.map(x => x.module.toString).mkString("\n")) +} diff --git a/generators/example/src/main/scala/System.scala b/generators/example/src/main/scala/System.scala new file mode 100644 index 00000000..1c62bf51 --- /dev/null +++ b/generators/example/src/main/scala/System.scala @@ -0,0 +1,63 @@ +//****************************************************************************** +// Copyright (c) 2019 - 2019, The Regents of the University of California (Regents). +// All Rights Reserved. See LICENSE and LICENSE.SiFive for license details. +//------------------------------------------------------------------------------ + +package example + +import chisel3._ + +import freechips.rocketchip.config.{Parameters} +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.util.{DontTouch} + +// --------------------------------------------------------------------- +// Base system that uses the debug test module (dtm) to bringup the core +// --------------------------------------------------------------------- + +/** + * Base top with periphery devices and ports, and a BOOM + Rocket subsystem + */ +class System(implicit p: Parameters) extends Subsystem + with HasAsyncExtInterrupts + with CanHaveMasterAXI4MemPort + with CanHaveMasterAXI4MMIOPort + with CanHaveSlaveAXI4Port + with HasPeripheryBootROM +{ + override lazy val module = new SystemModule(this) + + // The sbus masters the cbus; here we convert TL-UH -> TL-UL + sbus.crossToBus(cbus, NoCrossing) + + // The cbus masters the pbus; which might be clocked slower + cbus.crossToBus(pbus, SynchronousCrossing()) + + // The fbus masters the sbus; both are TL-UH or TL-C + FlipRendering { implicit p => + sbus.crossFromBus(fbus, SynchronousCrossing()) + } + + // The sbus masters the mbus; here we convert TL-C -> TL-UH + private val BankedL2Params(nBanks, coherenceManager) = p(BankedL2Key) + private val (in, out, halt) = coherenceManager(this) + if (nBanks != 0) { + sbus.coupleTo("coherence_manager") { in :*= _ } + mbus.coupleFrom("coherence_manager") { _ :=* BankBinder(mbus.blockBytes * (nBanks-1)) :*= out } + } +} + +/** + * Base top module implementation with periphery devices and ports, and a BOOM + Rocket subsystem + */ +class SystemModule[+L <: System](_outer: L) extends SubsystemModuleImp(_outer) + with HasRTCModuleImp + with HasExtInterruptsModuleImp + with CanHaveMasterAXI4MemPortModuleImp + with CanHaveMasterAXI4MMIOPortModuleImp + with CanHaveSlaveAXI4PortModuleImp + with HasPeripheryBootROMModuleImp + with DontTouch diff --git a/generators/example/src/main/scala/TestHarness.scala b/generators/example/src/main/scala/TestHarness.scala index 778fcc81..61807f2e 100644 --- a/generators/example/src/main/scala/TestHarness.scala +++ b/generators/example/src/main/scala/TestHarness.scala @@ -14,8 +14,8 @@ import freechips.rocketchip.devices.debug.{Debug} // BOOM and/or Rocket Test Harness // ------------------------------- -case object BuildBoomRocketTop extends Field[(Clock, Bool, Parameters) => BoomRocketTopModule[BoomRocketTop]] -case object BuildBoomRocketTopWithDTM extends Field[(Clock, Bool, Parameters) => BoomRocketTopWithDTMModule[BoomRocketTopWithDTM]] +case object BuildTop extends Field[(Clock, Bool, Parameters) => TopModule[Top]] +case object BuildTopWithDTM extends Field[(Clock, Bool, Parameters) => TopWithDTMModule[TopWithDTM]] /** * Test harness using TSI to bringup the system @@ -28,7 +28,7 @@ class TestHarness(implicit val p: Parameters) extends Module { // force Chisel to rename module override def desiredName = "TestHarness" - val dut = p(BuildBoomRocketTop)(clock, reset.toBool, p) + val dut = p(BuildTop)(clock, reset.toBool, p) dut.debug := DontCare dut.connectSimAXIMem() @@ -63,7 +63,7 @@ class TestHarnessWithDTM(implicit p: Parameters) extends Module // force Chisel to rename module override def desiredName = "TestHarness" - val dut = p(BuildBoomRocketTopWithDTM)(clock, reset.toBool, p) + val dut = p(BuildTopWithDTM)(clock, reset.toBool, p) dut.reset := reset.asBool | dut.debug.ndreset dut.connectSimAXIMem() diff --git a/generators/example/src/main/scala/Top.scala b/generators/example/src/main/scala/Top.scala index b861fdec..bfb03e0c 100644 --- a/generators/example/src/main/scala/Top.scala +++ b/generators/example/src/main/scala/Top.scala @@ -16,63 +16,63 @@ import sifive.blocks.devices.gpio._ // BOOM and/or Rocket Top Level Systems // ------------------------------------ -class BoomRocketTop(implicit p: Parameters) extends boom.system.BoomRocketSystem +class Top(implicit p: Parameters) extends System with HasNoDebug with HasPeripherySerial { - override lazy val module = new BoomRocketTopModule(this) + override lazy val module = new TopModule(this) } -class BoomRocketTopModule[+L <: BoomRocketTop](l: L) extends boom.system.BoomRocketSystemModule(l) +class TopModule[+L <: Top](l: L) extends SystemModule(l) with HasNoDebugModuleImp with HasPeripherySerialModuleImp with DontTouch //--------------------------------------------------------------------------------------------------------- -class BoomRocketTopWithPWMTL(implicit p: Parameters) extends BoomRocketTop +class TopWithPWMTL(implicit p: Parameters) extends Top with HasPeripheryPWMTL { - override lazy val module = new BoomRocketTopWithPWMTLModule(this) + override lazy val module = new TopWithPWMTLModule(this) } -class BoomRocketTopWithPWMTLModule(l: BoomRocketTopWithPWMTL) extends BoomRocketTopModule(l) +class TopWithPWMTLModule(l: TopWithPWMTL) extends TopModule(l) with HasPeripheryPWMTLModuleImp //--------------------------------------------------------------------------------------------------------- -class BoomRocketTopWithPWMAXI4(implicit p: Parameters) extends BoomRocketTop +class TopWithPWMAXI4(implicit p: Parameters) extends Top with HasPeripheryPWMAXI4 { - override lazy val module = new BoomRocketTopWithPWMAXI4Module(this) + override lazy val module = new TopWithPWMAXI4Module(this) } -class BoomRocketTopWithPWMAXI4Module(l: BoomRocketTopWithPWMAXI4) extends BoomRocketTopModule(l) +class TopWithPWMAXI4Module(l: TopWithPWMAXI4) extends TopModule(l) with HasPeripheryPWMAXI4ModuleImp //--------------------------------------------------------------------------------------------------------- -class BoomRocketTopWithBlockDevice(implicit p: Parameters) extends BoomRocketTop +class TopWithBlockDevice(implicit p: Parameters) extends Top with HasPeripheryBlockDevice { - override lazy val module = new BoomRocketTopWithBlockDeviceModule(this) + override lazy val module = new TopWithBlockDeviceModule(this) } -class BoomRocketTopWithBlockDeviceModule(l: BoomRocketTopWithBlockDevice) extends BoomRocketTopModule(l) +class TopWithBlockDeviceModule(l: TopWithBlockDevice) extends TopModule(l) with HasPeripheryBlockDeviceModuleImp //--------------------------------------------------------------------------------------------------------- -class BoomRocketTopWithGPIO(implicit p: Parameters) extends BoomRocketTop - with HasPeripheryGPIO { - override lazy val module = new BoomRocketTopWithGPIOModule(this) +class TopWithGPIO(implicit p: Parameters) extends Top + with HasPeripheryGPIO { + override lazy val module = new TopWithGPIOModule(this) } -class BoomRocketTopWithGPIOModule(l: BoomRocketTopWithGPIO) - extends BoomRocketTopModule(l) +class TopWithGPIOModule(l: TopWithGPIO) + extends TopModule(l) with HasPeripheryGPIOModuleImp //--------------------------------------------------------------------------------------------------------- -class BoomRocketTopWithDTM(implicit p: Parameters) extends boom.system.BoomRocketSystem +class TopWithDTM(implicit p: Parameters) extends System { - override lazy val module = new BoomRocketTopWithDTMModule(this) + override lazy val module = new TopWithDTMModule(this) } -class BoomRocketTopWithDTMModule[+L <: BoomRocketTopWithDTM](l: L) extends boom.system.BoomRocketSystemModule(l) +class TopWithDTMModule[+L <: TopWithDTM](l: L) extends SystemModule(l) diff --git a/generators/utilities/src/main/scala/TestSuites.scala b/generators/utilities/src/main/scala/TestSuites.scala index ab0ff8d5..725e1e69 100644 --- a/generators/utilities/src/main/scala/TestSuites.scala +++ b/generators/utilities/src/main/scala/TestSuites.scala @@ -8,7 +8,7 @@ import freechips.rocketchip.config.{Parameters} import freechips.rocketchip.util.{GeneratorApp} import freechips.rocketchip.system.{TestGeneration, RegressionTestSuite} -import boom.system.{BoomTilesKey} +import boom.common.{BoomTilesKey} /** * A set of pre-chosen regression tests diff --git a/variables.mk b/variables.mk index ca0f8fc9..ddf05da8 100644 --- a/variables.mk +++ b/variables.mk @@ -32,11 +32,11 @@ ifeq ($(SUB_PROJECT),example) MODEL ?= TestHarness VLOG_MODEL ?= TestHarness MODEL_PACKAGE ?= $(SBT_PROJECT) - CONFIG ?= DefaultRocketConfig + CONFIG ?= RocketConfig CONFIG_PACKAGE ?= $(SBT_PROJECT) GENERATOR_PACKAGE ?= $(SBT_PROJECT) TB ?= TestDriver - TOP ?= BoomRocketTop + TOP ?= Top endif # for Rocket-chip developers ifeq ($(SUB_PROJECT),rocketchip) From ba3deac1de165f3bbbc660666d9fddc40521ca4e Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 26 Aug 2019 14:50:46 -0700 Subject: [PATCH 11/91] Update CI with new config names --- .circleci/config.yml | 62 ------------------------------------------- .circleci/defaults.sh | 7 +++-- 2 files changed, 3 insertions(+), 66 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1ae4a000..107749e5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -117,35 +117,6 @@ jobs: key: example-{{ .Branch }}-{{ .Revision }} paths: - "/home/riscvuser/project" - prepare-boomexample: - docker: - - image: riscvboom/riscvboom-images:0.0.10 - 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-v1-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Building the boomexample subproject using Verilator - command: .circleci/do-rtl-build.sh boomexample - no_output_timeout: 120m - - save_cache: - key: boomexample-{{ .Branch }}-{{ .Revision }} - paths: - - "/home/riscvuser/project" prepare-boomrocketexample: docker: - image: riscvboom/riscvboom-images:0.0.10 @@ -315,30 +286,6 @@ jobs: - run: name: Run example tests command: .circleci/run-tests.sh example - boomexample-run-tests: - docker: - - image: riscvboom/riscvboom-images:0.0.10 - 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-v1-{{ checksum "../riscv-tools.hash" }} - - restore_cache: - keys: - - boomexample-{{ .Branch }}-{{ .Revision }} - - restore_cache: - keys: - - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} - - run: - name: Run boomexample tests - command: .circleci/run-tests.sh boomexample boomrocketexample-run-tests: docker: - image: riscvboom/riscvboom-images:0.0.10 @@ -468,11 +415,6 @@ workflows: - install-riscv-toolchain - install-verilator - - prepare-boomexample: - requires: - - install-riscv-toolchain - - install-verilator - - prepare-boomrocketexample: requires: - install-riscv-toolchain @@ -505,10 +447,6 @@ workflows: requires: - prepare-example - - boomexample-run-tests: - requires: - - prepare-boomexample - - boomrocketexample-run-tests: requires: - prepare-boomrocketexample diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index 439c4177..fb7a3571 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -36,9 +36,8 @@ LOCAL_SIM_DIR=$LOCAL_CHIPYARD_DIR/sims/verilator # key value store to get the build strings declare -A mapping mapping["example"]="SUB_PROJECT=example" -mapping["boomexample"]="SUB_PROJECT=example CONFIG=DefaultBoomConfig" -mapping["boomrocketexample"]="SUB_PROJECT=example CONFIG=DefaultBoomAndRocketConfig" +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=BoomRocketTopWithBlockDevice" -mapping["hwacha"]="SUB_PROJECT=example CONFIG=HwachaL2Config GENERATOR_PACKAGE=hwacha" +mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=SimBlockDeviceRocketConfig TOP=TopWithBlockDevice" +mapping["hwacha"]="SUB_PROJECT=example CONFIG=HwachaRocketConfig GENERATOR_PACKAGE=hwacha" From 19282fd438d376e2dc11ca5b2d2603d117d22b9e Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 26 Aug 2019 14:51:20 -0700 Subject: [PATCH 12/91] Update FireChip with the new locations for subsystem --- generators/firechip/src/main/scala/Generator.scala | 4 ++-- generators/firechip/src/main/scala/TargetConfigs.scala | 2 +- generators/firechip/src/main/scala/Targets.scala | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/generators/firechip/src/main/scala/Generator.scala b/generators/firechip/src/main/scala/Generator.scala index 0dd0e1eb..7f8c796a 100644 --- a/generators/firechip/src/main/scala/Generator.scala +++ b/generators/firechip/src/main/scala/Generator.scala @@ -27,8 +27,8 @@ trait HasTestSuites { "rv64ud-v-fadd", "rv64uf-v-fadd", "rv64um-v-mul", - // "rv64mi-p-breakpoint", // Not implemented in BOOM - // "rv64uc-v-rvc", // Not implemented in BOOM + "rv64mi-p-breakpoint", + "rv64uc-v-rvc", "rv64ud-v-structural", "rv64si-p-wfi", "rv64um-v-divw", diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index c81fe843..3795784b 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -9,7 +9,7 @@ import freechips.rocketchip.tilelink._ import freechips.rocketchip.subsystem._ import freechips.rocketchip.devices.tilelink.BootROMParams import freechips.rocketchip.devices.debug.DebugModuleParams -import boom.system.BoomTilesKey +import boom.common.BoomTilesKey import testchipip.{WithBlockDevice, BlockDeviceKey, BlockDeviceConfig} import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} import icenet._ diff --git a/generators/firechip/src/main/scala/Targets.scala b/generators/firechip/src/main/scala/Targets.scala index 7f8bb830..8f122a2c 100644 --- a/generators/firechip/src/main/scala/Targets.scala +++ b/generators/firechip/src/main/scala/Targets.scala @@ -11,7 +11,7 @@ import freechips.rocketchip.util.{HeterogeneousBag} import freechips.rocketchip.amba.axi4.AXI4Bundle import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.diplomacy.LazyModule -import boom.system.{BoomRocketSubsystem, BoomRocketSubsystemModuleImp} +import example.{Subsystem, SubsystemModuleImp} import icenet._ import testchipip._ import testchipip.SerialAdapter.SERIAL_IF_WIDTH @@ -80,7 +80,7 @@ class FireSimNoNICModuleImp[+L <: FireSimNoNIC](l: L) extends RocketSubsystemMod with HasTraceIOImp -class FireBoom(implicit p: Parameters) extends BoomRocketSubsystem +class FireBoom(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology with CanHaveFASEDOptimizedMasterAXI4MemPort with HasPeripheryBootROM @@ -94,7 +94,7 @@ class FireBoom(implicit p: Parameters) extends BoomRocketSubsystem override lazy val module = new FireBoomModuleImp(this) } -class FireBoomModuleImp[+L <: FireBoom](l: L) extends BoomRocketSubsystemModuleImp(l) +class FireBoomModuleImp[+L <: FireBoom](l: L) extends SubsystemModuleImp(l) with HasRTCModuleImp with CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp @@ -106,7 +106,7 @@ class FireBoomModuleImp[+L <: FireBoom](l: L) extends BoomRocketSubsystemModuleI with HasTraceIOImp with ExcludeInvalidBoomAssertions -class FireBoomNoNIC(implicit p: Parameters) extends BoomRocketSubsystem +class FireBoomNoNIC(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology with CanHaveFASEDOptimizedMasterAXI4MemPort with HasPeripheryBootROM @@ -119,7 +119,7 @@ class FireBoomNoNIC(implicit p: Parameters) extends BoomRocketSubsystem override lazy val module = new FireBoomNoNICModuleImp(this) } -class FireBoomNoNICModuleImp[+L <: FireBoomNoNIC](l: L) extends BoomRocketSubsystemModuleImp(l) +class FireBoomNoNICModuleImp[+L <: FireBoomNoNIC](l: L) extends SubsystemModuleImp(l) with HasRTCModuleImp with CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp From 832d5585172f46416afbd7fa80e19298eb6cd45a Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 26 Aug 2019 15:56:51 -0700 Subject: [PATCH 13/91] Update FireChip reference to boom configs --- generators/example/src/main/scala/Configs.scala | 2 +- generators/firechip/src/main/scala/TargetConfigs.scala | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/generators/example/src/main/scala/Configs.scala b/generators/example/src/main/scala/Configs.scala index 5004e6ee..ede2701b 100644 --- a/generators/example/src/main/scala/Configs.scala +++ b/generators/example/src/main/scala/Configs.scala @@ -13,7 +13,7 @@ class RocketConfig extends Config( new WithBootROM ++ // use default bootrom 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 (implicitly creates Rocket cores) + new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system class HwachaRocketConfig extends Config( new WithTop ++ diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 3795784b..85c82753 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -136,8 +136,10 @@ class FireSimBoomConfig extends Config( new WithBlockDevice ++ new WithBoomL2TLBs(1024) ++ new WithoutClockGating ++ - // Using a small config because it has 64-bit system bus, and compiles quickly - new boom.common.SmallBoomConfig) + new boom.common.WithLargeBooms ++ + new boom.common.WithNBoomCores(1) ++ + new freechips.rocketchip.system.BaseConfig +) // A safer implementation than the one in BOOM in that it // duplicates whatever BOOMTileKey.head is present N times. This prevents From 93c3a2cd723816f1fa7403db4ce2ba717b9b110e Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 26 Aug 2019 16:29:54 -0700 Subject: [PATCH 14/91] Rename Configs -> RocketConfigs --- .../example/src/main/scala/{Configs.scala => RocketConfigs.scala} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename generators/example/src/main/scala/{Configs.scala => RocketConfigs.scala} (100%) diff --git a/generators/example/src/main/scala/Configs.scala b/generators/example/src/main/scala/RocketConfigs.scala similarity index 100% rename from generators/example/src/main/scala/Configs.scala rename to generators/example/src/main/scala/RocketConfigs.scala From 939ce4ea175c2c5788c8abb78dc134ad76d42d88 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 26 Aug 2019 16:31:10 -0700 Subject: [PATCH 15/91] Fix Config comments --- .../example/src/main/scala/BoomConfigs.scala | 4 ++-- .../example/src/main/scala/HeteroConfigs.scala | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/generators/example/src/main/scala/BoomConfigs.scala b/generators/example/src/main/scala/BoomConfigs.scala index c97154aa..7da54ffa 100644 --- a/generators/example/src/main/scala/BoomConfigs.scala +++ b/generators/example/src/main/scala/BoomConfigs.scala @@ -11,10 +11,10 @@ import freechips.rocketchip.config.{Config} class SmallBoomConfig extends Config( new WithTop ++ // use normal top new WithBootROM ++ // use testchipip bootrom - new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache + 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 + new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system class MediumBoomConfig extends Config( new WithTop ++ diff --git a/generators/example/src/main/scala/HeteroConfigs.scala b/generators/example/src/main/scala/HeteroConfigs.scala index 898991d7..8c966bc2 100644 --- a/generators/example/src/main/scala/HeteroConfigs.scala +++ b/generators/example/src/main/scala/HeteroConfigs.scala @@ -9,14 +9,14 @@ import freechips.rocketchip.config.{Config} // --------------------- class LargeBoomAndRocketConfig extends Config( - new WithTop ++ // default top - new WithBootROM ++ // default bootrom - new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive l2 - new boom.common.WithRenumberHarts ++ // avoid hartid overlap - new boom.common.WithLargeBooms ++ // 3-wide boom - new boom.common.WithNBoomCores(1) ++ // single-core boom - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single-core rocket - new freechips.rocketchip.system.BaseConfig) // "Base" rocketchip system + new WithTop ++ // default top + new WithBootROM ++ // default bootrom + new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use SiFive l2 + new boom.common.WithRenumberHarts ++ // avoid hartid overlap + new boom.common.WithLargeBooms ++ // 3-wide boom + new boom.common.WithNBoomCores(1) ++ // single-core boom + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single-core rocket + new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system class HwachaLargeBoomAndHwachaRocketConfig extends Config( new WithTop ++ From f221c8f26e8e47d4f192f9ed8cb74ad748289751 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 26 Aug 2019 20:15:01 -0700 Subject: [PATCH 16/91] Bump boomrocket example CI build time --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 107749e5..77a813ee 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -141,7 +141,7 @@ jobs: - run: name: Building the boomrocketexample subproject using Verilator command: .circleci/do-rtl-build.sh boomrocketexample - no_output_timeout: 120m + no_output_timeout: 240m - save_cache: key: boomrocketexample-{{ .Branch }}-{{ .Revision }} paths: From 20b6737889dd4b90cf02daa54d305a55c821d1a8 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 26 Aug 2019 23:28:35 -0700 Subject: [PATCH 17/91] Add remaining configs for BOOM CI --- generators/example/src/main/scala/BoomConfigs.scala | 1 + generators/example/src/main/scala/HeteroConfigs.scala | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/generators/example/src/main/scala/BoomConfigs.scala b/generators/example/src/main/scala/BoomConfigs.scala index 7da54ffa..c6521619 100644 --- a/generators/example/src/main/scala/BoomConfigs.scala +++ b/generators/example/src/main/scala/BoomConfigs.scala @@ -61,6 +61,7 @@ class SmallRV32UnifiedBoomConfig extends Config( new WithTop ++ new WithBootROM ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithoutBoomFPU ++ // no floating point new boom.common.WithUnifiedMemIntIQs ++ // use unified mem+int issue queues new boom.common.WithSmallBooms ++ new boom.common.WithNBoomCores(1) ++ diff --git a/generators/example/src/main/scala/HeteroConfigs.scala b/generators/example/src/main/scala/HeteroConfigs.scala index 8c966bc2..6f7cf8b1 100644 --- a/generators/example/src/main/scala/HeteroConfigs.scala +++ b/generators/example/src/main/scala/HeteroConfigs.scala @@ -18,6 +18,16 @@ class LargeBoomAndRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single-core rocket new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system +class SmallBoomAndRocketConfig extends Config( + new WithTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new boom.common.WithRenumberHarts ++ + new boom.common.WithSmallBooms ++ // 1-wide boom + new boom.common.WithNBoomCores(1) ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) + class HwachaLargeBoomAndHwachaRocketConfig extends Config( new WithTop ++ new WithBootROM ++ From 65003f86d0d5dbb37897666c7a9b06ad672079de Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 26 Aug 2019 23:29:50 -0700 Subject: [PATCH 18/91] Bump boom --- generators/boom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/boom b/generators/boom index 793912ee..fb184407 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit 793912eef8a9f09c13bd791c33ba682350a6026a +Subproject commit fb184407e93183353a3286a8c8ec9bf6660ff352 From 1d85dc32a07cc391ee1763f71eef17ba14f2b858 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Tue, 27 Aug 2019 12:00:50 -0700 Subject: [PATCH 19/91] Use HasHierarchicalBusTopology mixin --- .../example/src/main/scala/System.scala | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/generators/example/src/main/scala/System.scala b/generators/example/src/main/scala/System.scala index 1c62bf51..3b39ff80 100644 --- a/generators/example/src/main/scala/System.scala +++ b/generators/example/src/main/scala/System.scala @@ -22,6 +22,7 @@ import freechips.rocketchip.util.{DontTouch} * Base top with periphery devices and ports, and a BOOM + Rocket subsystem */ class System(implicit p: Parameters) extends Subsystem + with HasHierarchicalBusTopology with HasAsyncExtInterrupts with CanHaveMasterAXI4MemPort with CanHaveMasterAXI4MMIOPort @@ -29,25 +30,6 @@ class System(implicit p: Parameters) extends Subsystem with HasPeripheryBootROM { override lazy val module = new SystemModule(this) - - // The sbus masters the cbus; here we convert TL-UH -> TL-UL - sbus.crossToBus(cbus, NoCrossing) - - // The cbus masters the pbus; which might be clocked slower - cbus.crossToBus(pbus, SynchronousCrossing()) - - // The fbus masters the sbus; both are TL-UH or TL-C - FlipRendering { implicit p => - sbus.crossFromBus(fbus, SynchronousCrossing()) - } - - // The sbus masters the mbus; here we convert TL-C -> TL-UH - private val BankedL2Params(nBanks, coherenceManager) = p(BankedL2Key) - private val (in, out, halt) = coherenceManager(this) - if (nBanks != 0) { - sbus.coupleTo("coherence_manager") { in :*= _ } - mbus.coupleFrom("coherence_manager") { _ :=* BankBinder(mbus.blockBytes * (nBanks-1)) :*= out } - } } /** From ca70c1544709843452d17d9045da30981f8101d6 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Tue, 27 Aug 2019 17:34:50 -0700 Subject: [PATCH 20/91] Remove TracedBoomConfig --- generators/example/src/main/scala/BoomConfigs.scala | 9 --------- 1 file changed, 9 deletions(-) diff --git a/generators/example/src/main/scala/BoomConfigs.scala b/generators/example/src/main/scala/BoomConfigs.scala index c6521619..59654ea5 100644 --- a/generators/example/src/main/scala/BoomConfigs.scala +++ b/generators/example/src/main/scala/BoomConfigs.scala @@ -48,15 +48,6 @@ class DualSmallBoomConfig extends Config( new boom.common.WithNBoomCores(2) ++ // dual-core new freechips.rocketchip.system.BaseConfig) -class TracedSmallBoomConfig extends Config( - new WithTop ++ - new WithBootROM ++ - new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new boom.common.WithTrace ++ // enable trace port on BOOM - new boom.common.WithSmallBooms ++ - new boom.common.WithNBoomCores(1) ++ - new freechips.rocketchip.system.BaseConfig) - class SmallRV32UnifiedBoomConfig extends Config( new WithTop ++ new WithBootROM ++ From f1929a0da816fd0bcd84e47c46cdbd8975d44425 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Tue, 27 Aug 2019 18:05:24 -0700 Subject: [PATCH 21/91] Move System/Subsystem to utilities --- generators/example/src/main/scala/Top.scala | 2 ++ generators/firechip/src/main/scala/Targets.scala | 2 +- .../{example => utilities}/src/main/scala/Subsystem.scala | 2 +- generators/{example => utilities}/src/main/scala/System.scala | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) rename generators/{example => utilities}/src/main/scala/Subsystem.scala (99%) rename generators/{example => utilities}/src/main/scala/System.scala (98%) diff --git a/generators/example/src/main/scala/Top.scala b/generators/example/src/main/scala/Top.scala index bfb03e0c..19990817 100644 --- a/generators/example/src/main/scala/Top.scala +++ b/generators/example/src/main/scala/Top.scala @@ -10,6 +10,8 @@ import freechips.rocketchip.util.DontTouch import testchipip._ +import utilities.{System, SystemModule} + import sifive.blocks.devices.gpio._ // ------------------------------------ diff --git a/generators/firechip/src/main/scala/Targets.scala b/generators/firechip/src/main/scala/Targets.scala index 8f122a2c..7b6ea95c 100644 --- a/generators/firechip/src/main/scala/Targets.scala +++ b/generators/firechip/src/main/scala/Targets.scala @@ -11,7 +11,7 @@ import freechips.rocketchip.util.{HeterogeneousBag} import freechips.rocketchip.amba.axi4.AXI4Bundle import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.diplomacy.LazyModule -import example.{Subsystem, SubsystemModuleImp} +import utilities.{Subsystem, SubsystemModuleImp} import icenet._ import testchipip._ import testchipip.SerialAdapter.SERIAL_IF_WIDTH diff --git a/generators/example/src/main/scala/Subsystem.scala b/generators/utilities/src/main/scala/Subsystem.scala similarity index 99% rename from generators/example/src/main/scala/Subsystem.scala rename to generators/utilities/src/main/scala/Subsystem.scala index 7888bc4f..58bc342d 100644 --- a/generators/example/src/main/scala/Subsystem.scala +++ b/generators/utilities/src/main/scala/Subsystem.scala @@ -3,7 +3,7 @@ // All Rights Reserved. See LICENSE and LICENSE.SiFive for license details. //------------------------------------------------------------------------------ -package example +package utilities import chisel3._ import chisel3.internal.sourceinfo.{SourceInfo} diff --git a/generators/example/src/main/scala/System.scala b/generators/utilities/src/main/scala/System.scala similarity index 98% rename from generators/example/src/main/scala/System.scala rename to generators/utilities/src/main/scala/System.scala index 3b39ff80..0eed6660 100644 --- a/generators/example/src/main/scala/System.scala +++ b/generators/utilities/src/main/scala/System.scala @@ -3,7 +3,7 @@ // All Rights Reserved. See LICENSE and LICENSE.SiFive for license details. //------------------------------------------------------------------------------ -package example +package utilities import chisel3._ From 4de40d3863670fd4dc7e7359b2e163d09bb09ff6 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Wed, 28 Aug 2019 14:53:24 -0700 Subject: [PATCH 22/91] Update naming in docs --- docs/Advanced-Usage/DTM-Debugging.rst | 6 +++--- docs/Chipyard-Basics/Running-A-Simulation.rst | 6 ------ docs/Customization/Heterogeneous-SoCs.rst | 16 ++++++++-------- docs/Simulation/Software-RTL-Simulators.rst | 12 ++++++------ 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/docs/Advanced-Usage/DTM-Debugging.rst b/docs/Advanced-Usage/DTM-Debugging.rst index bf033fec..839e36a0 100644 --- a/docs/Advanced-Usage/DTM-Debugging.rst +++ b/docs/Advanced-Usage/DTM-Debugging.rst @@ -16,12 +16,12 @@ This involves specifying the SoC top-level to add a DTM as well as configuring t .. code-block:: scala class DTMBoomConfig extends Config( - new WithDTMBoomRocketTop ++ + new WithDTMTop ++ new WithBootROM ++ new WithJtagDTM ++ new boom.common.SmallBoomConfig) -In this example, the ``WithDTMBoomRocketTop`` mixin specifies that the top-level SoC will instantiate a DTM. +In this example, the ``WithDTMTop`` mixin specifies that the top-level SoC will instantiate a DTM. The ``WithJtagDTM`` will configure that instantiated DTM to use JTAG as the bringup method (note: this can be removed if you want a DTM-only bringup). The rest of the mixins specify the rest of the system (cores, accelerators, etc). @@ -36,7 +36,7 @@ After creating the config, call the ``make`` command like the following: # or cd sims/vcs - make CONFIG=DTMBoomConfig TOP=BoomRocketTopWithDTM MODEL=TestHarnessWithDTM + make CONFIG=DTMBoomConfig TOP=TopWithDTM MODEL=TestHarnessWithDTM In this example, this will use the config that you previously specified, as well as set the other parameters that are needed to satisfy the build system. After that point, you should have a JTAG enabled simulation that you can attach to using OpenOCD and GDB! diff --git a/docs/Chipyard-Basics/Running-A-Simulation.rst b/docs/Chipyard-Basics/Running-A-Simulation.rst index 39128f30..7b3f0cc1 100644 --- a/docs/Chipyard-Basics/Running-A-Simulation.rst +++ b/docs/Chipyard-Basics/Running-A-Simulation.rst @@ -58,12 +58,6 @@ Therefore, in order to simulate a simple Rocket-based example system we can use: make SUB_PROJECT=example -Alternatively, if we would like to simulate a simple BOOM-based example system we can use: - -.. code-block:: shell - - make SUB_PROJECT=exampleboom - Once the simulator has been constructed, we would like to run RISC-V programs on it. In the simulation directory, we will find an executable file called ``<...>--``. We run this executable with our target RISC-V program as a command line argument in one of two ways. diff --git a/docs/Customization/Heterogeneous-SoCs.rst b/docs/Customization/Heterogeneous-SoCs.rst index 96a7e40e..c1a6a003 100644 --- a/docs/Customization/Heterogeneous-SoCs.rst +++ b/docs/Customization/Heterogeneous-SoCs.rst @@ -15,18 +15,18 @@ The following example shows a dual core BOOM with a single core Rocket. .. code-block:: scala class DualBoomAndOneRocketConfig extends Config( - new WithNormalBoomRocketTop ++ + new WithTop ++ new WithBootROM ++ new boom.system.WithRenumberHarts ++ new boom.common.WithRVC ++ - new boom.common.DefaultBoomConfig ++ + new boom.common.LargeBoomConfig ++ new boom.system.WithNBoomCores(2) ++ new freechips.rocketchip.subsystem.WithoutTLMonitors ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) 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 ``DefaultBoomConfig`` is added to override the default parameters with a different set of more common default parameters. +However, for BOOM, an extra mixin called ``LargeBoomConfig`` 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. @@ -62,7 +62,7 @@ Then you could use this new mixin like the following. .. code-block:: scala class SixCoreConfig extends Config( - new WithNormalBoomRocketTop ++ + new WithTop ++ new WithBootROM ++ new WithHeterCoresSetup ++ new freechips.rocketchip.system.BaseConfig) @@ -78,12 +78,12 @@ An example of adding a Hwacha to all tiles in the system is below. .. code-block:: scala class DualBoomAndRocketWithHwachasConfig extends Config( - new WithNormalBoomRocketTop ++ + new WithTop ++ new WithBootROM ++ new hwacha.DefaultHwachaConfig ++ new boom.system.WithRenumberHarts ++ new boom.common.WithRVC ++ - new boom.common.DefaultBoomConfig ++ + new boom.common.LargeBoomConfig ++ new boom.system.WithNBoomCores(2) ++ new freechips.rocketchip.subsystem.WithoutTLMonitors ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ @@ -103,14 +103,14 @@ An example is shown below with two BOOM cores, and one Rocket tile with a RoCC a .. code-block:: scala class DualBoomAndOneHwachaRocketConfig extends Config( - new WithNormalBoomRocketTop ++ + new WithTop ++ new WithBootROM ++ new WithMultiRoCC ++ new WithMultiRoCCHwacha(0) ++ // put Hwacha just on hart0 which was renumbered to Rocket new boom.system.WithRenumberHarts(rocketFirst = true) ++ new hwacha.DefaultHwachaConfig ++ new boom.common.WithRVC ++ - new boom.common.DefaultBoomConfig ++ + new boom.common.LargeBoomConfig ++ new boom.system.WithNBoomCores(2) ++ new freechips.rocketchip.subsystem.WithoutTLMonitors ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ diff --git a/docs/Simulation/Software-RTL-Simulators.rst b/docs/Simulation/Software-RTL-Simulators.rst index 89bd337c..5dd4e527 100644 --- a/docs/Simulation/Software-RTL-Simulators.rst +++ b/docs/Simulation/Software-RTL-Simulators.rst @@ -12,16 +12,16 @@ The Chipyard framework can download, build, and execute simulations using Verila To run a simulation using Verilator, perform the following steps: To compile the example design, run ``make`` in the ``sims/verilator`` directory. -This will elaborate the ``DefaultRocketConfig`` in the example project. +This will elaborate the ``RocketConfig`` in the example project. -An executable called ``simulator-example-DefaultRocketConfig`` will be produced. +An executable called ``simulator-example-RocketConfig`` will be produced. This executable is a simulator that has been compiled based on the design that was built. You can then use this executable to run any compatible RV64 code. For instance, to run one of the riscv-tools assembly tests. .. code-block:: shell - ./simulator-example-DefaultRocketConfig $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-simple + ./simulator-example-RocketConfig $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-simple If you later create your own project, you can use environment variables to build an alternate configuration. @@ -50,16 +50,16 @@ To run a simulation using VCS, perform the following steps: Make sure that the VCS simulator is on your ``PATH``. To compile the example design, run make in the ``sims/vcs`` directory. -This will elaborate the ``DefaultRocketConfig`` in the example project. +This will elaborate the ``RocketConfig`` in the example project. -An executable called ``simulator-example-DefaultRocketConfig`` will be produced. +An executable called ``simulator-example-RocketConfig`` will be produced. This executable is a simulator that has been compiled based on the design that was built. You can then use this executable to run any compatible RV64 code. For instance, to run one of the riscv-tools assembly tests. .. code-block:: shell - ./simulator-example-DefaultRocketConfig $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-simple + ./simulator-example-RocketConfig $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-simple If you later create your own project, you can use environment variables to build an alternate configuration. From 71b3d7e1e688267d175cdced81307c662fe11f03 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 29 Aug 2019 18:50:43 -0700 Subject: [PATCH 23/91] Force verilator to produce fragmented cpp files --- sims/verilator/Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sims/verilator/Makefile b/sims/verilator/Makefile index 31fc2d41..2fcb79d1 100644 --- a/sims/verilator/Makefile +++ b/sims/verilator/Makefile @@ -59,7 +59,8 @@ VERILATOR_NONCC_OPTS = \ +define+PRINTF_COND=\$$c\(\"verbose\",\"\&\&\"\,\"done_reset\"\) \ +define+STOP_COND=\$$c\(\"done_reset\"\) \ --assert \ - --output-split 20000 \ + --output-split 10000 \ + --output-split-cfuncs 100 \ $(sim_vsrcs) \ -f $(sim_common_files) @@ -96,11 +97,12 @@ $(model_mk_debug): $(sim_vsrcs) $(sim_common_files) $(INSTALLED_VERILATOR) ######################################################################################### # invoke make to make verilator sim rules ######################################################################################### +VERILATOR_MAKEFLAGS=-j8 $(sim): $(model_mk) - $(MAKE) VM_PARALLEL_BUILDS=1 -C $(model_dir) -f V$(VLOG_MODEL).mk + $(MAKE) $(VERILATOR_MAKEFLAGS) VM_PARALLEL_BUILDS=1 -C $(model_dir) -f V$(VLOG_MODEL).mk $(sim_debug): $(model_mk_debug) - $(MAKE) VM_PARALLEL_BUILDS=1 -C $(model_dir_debug) -f V$(VLOG_MODEL).mk + $(MAKE) $(VERILATOR_MAKEFLAGS) VM_PARALLEL_BUILDS=1 -C $(model_dir_debug) -f V$(VLOG_MODEL).mk ######################################################################################### # create a verilator vpd rule From 648780601c3b149a2de0f8695be0a936071ab854 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 29 Aug 2019 22:53:41 -0700 Subject: [PATCH 24/91] Bump boom to version which passes ci --- generators/boom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/boom b/generators/boom index fb184407..7b68d748 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit fb184407e93183353a3286a8c8ec9bf6660ff352 +Subproject commit 7b68d748b6c09d2403ba500590a8e32f5963c407 From d363ad5a460a84fa920e260b84d420f7bfc749c2 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 29 Aug 2019 23:04:06 -0700 Subject: [PATCH 25/91] Fix tabs vs spaces in sims/verilator/Makefile --- sims/verilator/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/verilator/Makefile b/sims/verilator/Makefile index 2fcb79d1..3763f627 100644 --- a/sims/verilator/Makefile +++ b/sims/verilator/Makefile @@ -59,7 +59,7 @@ VERILATOR_NONCC_OPTS = \ +define+PRINTF_COND=\$$c\(\"verbose\",\"\&\&\"\,\"done_reset\"\) \ +define+STOP_COND=\$$c\(\"done_reset\"\) \ --assert \ - --output-split 10000 \ + --output-split 10000 \ --output-split-cfuncs 100 \ $(sim_vsrcs) \ -f $(sim_common_files) From fc380b2ddab205f61d8d4c67cbb15b30770be93a Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Thu, 29 Aug 2019 23:43:08 -0700 Subject: [PATCH 26/91] ignore docs using a github webhook --- .ciignore | 1 + .githooks/ignore-certain-dirs-commit-msg | 31 ++++++++++++++++++++++++ scripts/add-githooks.sh | 5 ++++ 3 files changed, 37 insertions(+) create mode 100644 .ciignore create mode 100644 .githooks/ignore-certain-dirs-commit-msg create mode 100755 scripts/add-githooks.sh diff --git a/.ciignore b/.ciignore new file mode 100644 index 00000000..a188e069 --- /dev/null +++ b/.ciignore @@ -0,0 +1 @@ +docs/* diff --git a/.githooks/ignore-certain-dirs-commit-msg b/.githooks/ignore-certain-dirs-commit-msg new file mode 100644 index 00000000..3ab0e7b4 --- /dev/null +++ b/.githooks/ignore-certain-dirs-commit-msg @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +if [[ ! -a .ciignore ]]; then + exit # If .ciignore doesn't exists, just quit this Git hook +fi + +# Load in every file that will be changed via this commit into an array +changes=( `git diff --name-only --cached` ) + +# Load the patterns we want to skip into an array +mapfile -t blacklist < .ciignore + +for i in "${blacklist[@]}" +do + # Remove the current pattern from the list of changes + changes=( ${changes[@]/$i/} ) + + if [[ ${#changes[@]} -eq 0 ]]; then + # If we've exhausted the list of changes before we've finished going + # through patterns, that's okay, just quit the loop + break + fi +done + +if [[ ${#changes[@]} -gt 0 ]]; then + # If there's still changes left, then we have stuff to build, leave the commit alone. + exit +fi + +# Prefix the commit message with "[skip ci]" +sed -i '1s/^/[skip ci] /' "$1" diff --git a/scripts/add-githooks.sh b/scripts/add-githooks.sh new file mode 100755 index 00000000..fb5e4785 --- /dev/null +++ b/scripts/add-githooks.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +# adds githooks, expects to be run from base directory + +git config core.hooksPath .githooks From c9c166f4a6c234fb1ff7aa3971784d7ae101c41b Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 30 Aug 2019 01:27:14 -0700 Subject: [PATCH 27/91] comment on the sim_* variables --- common.mk | 4 ++-- variables.mk | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/common.mk b/common.mk index 16208e82..d920cf4d 100644 --- a/common.mk +++ b/common.mk @@ -31,7 +31,7 @@ $(FIRRTL_JAR): $(call lookup_scala_srcs, $(CHIPYARD_FIRRTL_DIR)/src/main/scala) touch $@ ######################################################################################### -# create simulation args file rule +# create list of simulation file inputs ######################################################################################### $(sim_files): $(call lookup_scala_srcs,$(base_dir)/generators/utilities/src/main/scala) $(FIRRTL_JAR) cd $(base_dir) && $(SBT) "project utilities" "runMain utilities.GenerateSimFiles -td $(build_dir) -sim $(sim_name)" @@ -65,7 +65,7 @@ $(HARNESS_SMEMS_FILE) $(HARNESS_SMEMS_FIR): $(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)" ######################################################################################## -# remove duplicate files in blackbox/simfiles +# 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' > $@ diff --git a/variables.mk b/variables.mk index 41d5ef81..6a0c5e1b 100644 --- a/variables.mk +++ b/variables.mk @@ -113,9 +113,11 @@ HARNESS_SMEMS_FILE ?= $(build_dir)/$(long_name).harness.mems.v HARNESS_SMEMS_CONF ?= $(build_dir)/$(long_name).harness.mems.conf HARNESS_SMEMS_FIR ?= $(build_dir)/$(long_name).harness.mems.fir +# files that contain lists of files needed for VCS or Verilator simulation sim_files ?= $(build_dir)/sim_files.f sim_top_blackboxes ?= $(build_dir)/firrtl_black_box_resource_files.top.f sim_harness_blackboxes ?= $(build_dir)/firrtl_black_box_resource_files.harness.f +# single file that contains all files needed for VCS or Verilator simulation (unique and without .h's) sim_common_files ?= $(build_dir)/sim_files.common.f ######################################################################################### From 6a3212c6d7f6485b69d1f4d7780089fa510d60c9 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 15 Jul 2019 16:36:12 -0700 Subject: [PATCH 28/91] add tracegen project --- build.sbt | 6 +- .../src/main/scala/TargetConfigs.scala | 70 +++++++++++++++++ .../src/main/scala/TargetMixins.scala | 1 - .../firechip/src/main/scala/Targets.scala | 12 +++ .../tracegen/src/main/scala/Configs.scala | 76 +++++++++++++++++++ .../tracegen/src/main/scala/System.scala | 43 +++++++++++ .../tracegen/src/main/scala/TestHarness.scala | 27 +++++++ generators/tracegen/src/main/scala/Tile.scala | 53 +++++++++++++ variables.mk | 11 +++ 9 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 generators/tracegen/src/main/scala/Configs.scala create mode 100644 generators/tracegen/src/main/scala/System.scala create mode 100644 generators/tracegen/src/main/scala/TestHarness.scala create mode 100644 generators/tracegen/src/main/scala/Tile.scala diff --git a/build.sbt b/build.sbt index d353a497..8e09a6ab 100644 --- a/build.sbt +++ b/build.sbt @@ -109,6 +109,10 @@ lazy val example = conditionalDependsOn(project in file("generators/example")) .dependsOn(boom, hwacha, sifive_blocks, sifive_cache, utilities) .settings(commonSettings) +lazy val tracegen = conditionalDependsOn(project in file("generators/tracegen")) + .dependsOn(rocketchip, sifive_cache) + .settings(commonSettings) + lazy val utilities = conditionalDependsOn(project in file("generators/utilities")) .dependsOn(rocketchip, boom) .settings(commonSettings) @@ -166,7 +170,7 @@ lazy val midas = ProjectRef(firesimDir, "midas") lazy val firesimLib = ProjectRef(firesimDir, "firesimLib") lazy val firechip = (project in file("generators/firechip")) - .dependsOn(boom, icenet, testchipip, sifive_blocks, sifive_cache, utilities, midasTargetUtils, midas, firesimLib % "test->test;compile->compile") + .dependsOn(boom, icenet, testchipip, sifive_blocks, sifive_cache, utilities, tracegen, midasTargetUtils, midas, firesimLib % "test->test;compile->compile") .settings( commonSettings, testGrouping in Test := isolateAllTests( (definedTests in Test).value ) diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index c81fe843..bab3ad1a 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -4,14 +4,18 @@ import java.io.File import chisel3.util.{log2Up} import freechips.rocketchip.config.{Parameters, Config} +import freechips.rocketchip.groundtest.TraceGenParams import freechips.rocketchip.tile._ import freechips.rocketchip.tilelink._ +import freechips.rocketchip.rocket.DCacheParams import freechips.rocketchip.subsystem._ import freechips.rocketchip.devices.tilelink.BootROMParams import freechips.rocketchip.devices.debug.DebugModuleParams import boom.system.BoomTilesKey import testchipip.{WithBlockDevice, BlockDeviceKey, BlockDeviceConfig} import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} +import scala.math.{min, max} +import tracegen.TraceGenKey import icenet._ class WithBootROM extends Config((site, here, up) => { @@ -203,3 +207,69 @@ class SupernodeFireSimRocketChipOctaCoreConfig extends Config( new WithExtMemSize(0x200000000L) ++ // 8GB new FireSimRocketChipOctaCoreConfig) +class WithTraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) + extends Config((site, here, up) => { + case TraceGenKey => 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 => log2Up(params.size) +}) + +class FireSimTraceGenConfig extends Config( + new WithTraceGen( + List.fill(2) { DCacheParams(nMSHRs = 2, nSets = 16, nWays = 2) }) ++ + new FireSimRocketChipConfig) + +class WithL2TraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) + extends Config((site, here, up) => { + case TraceGenKey => params.map { dcp => TraceGenParams( + dcache = Some(dcp), + wordBits = site(XLen), + addrBits = 48, + addrBag = { + val sbp = site(SystemBusKey) + val l2p = site(InclusiveCacheKey) + val nSets = max(l2p.sets, dcp.nSets) + val nWays = max(l2p.ways, dcp.nWays) + val nBanks = site(BankedL2Key).nBanks + val blockOffset = sbp.blockOffset + val nBeats = min(2, sbp.blockBeats) + val beatBytes = sbp.beatBytes + List.tabulate(2 * nWays) { i => + Seq.tabulate(nBeats) { j => + BigInt((j * beatBytes) + ((i * nSets * nBanks) << blockOffset)) + } + }.flatten + }, + maxRequests = nReqs, + memStart = site(ExtMem).get.master.base, + numGens = params.size) + } + case MaxHartIdBits => log2Up(params.size) +}) + +class FireSimTraceGenL2Config extends Config( + new WithL2TraceGen( + List.fill(2) { DCacheParams(nMSHRs = 2, nSets = 16, nWays = 2) }) ++ + new WithInclusiveCache( + nBanks = 4, + capacityKB = 1024, + outerLatencyCycles = 50) ++ + new FireSimRocketChipConfig) diff --git a/generators/firechip/src/main/scala/TargetMixins.scala b/generators/firechip/src/main/scala/TargetMixins.scala index 7b4d5d4f..199a22cc 100644 --- a/generators/firechip/src/main/scala/TargetMixins.scala +++ b/generators/firechip/src/main/scala/TargetMixins.scala @@ -103,4 +103,3 @@ trait HasTraceIOImp extends LazyModuleImp { trait ExcludeInvalidBoomAssertions extends LazyModuleImp { ExcludeInstanceAsserts(("NonBlockingDCache", "dtlb")) } - diff --git a/generators/firechip/src/main/scala/Targets.scala b/generators/firechip/src/main/scala/Targets.scala index 7f8bb830..616d64a1 100644 --- a/generators/firechip/src/main/scala/Targets.scala +++ b/generators/firechip/src/main/scala/Targets.scala @@ -15,6 +15,7 @@ import boom.system.{BoomRocketSubsystem, BoomRocketSubsystemModuleImp} import icenet._ import testchipip._ import testchipip.SerialAdapter.SERIAL_IF_WIDTH +import tracegen.{HasTraceGenTiles, HasTraceGenTilesModuleImp} import sifive.blocks.devices.uart._ import midas.models.AXI4BundleWithEdge import java.io.File @@ -174,3 +175,14 @@ class FireSimSupernode(implicit p: Parameters) extends Module { } } } +class FireSimTraceGen(implicit p: Parameters) extends BaseSubsystem + with HasHierarchicalBusTopology + with HasTraceGenTiles + with CanHaveFASEDOptimizedMasterAXI4MemPort { + override lazy val module = new FireSimTraceGenModuleImp(this) +} + +class FireSimTraceGenModuleImp(outer: FireSimTraceGen) + extends BaseSubsystemModuleImp(outer) + with HasTraceGenTilesModuleImp + with CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp diff --git a/generators/tracegen/src/main/scala/Configs.scala b/generators/tracegen/src/main/scala/Configs.scala new file mode 100644 index 00000000..e3536e6a --- /dev/null +++ b/generators/tracegen/src/main/scala/Configs.scala @@ -0,0 +1,76 @@ +package tracegen + +import chisel3._ +import chisel3.util.log2Ceil +import freechips.rocketchip.config.{Config, Parameters} +import freechips.rocketchip.groundtest.{TraceGenParams} +import freechips.rocketchip.subsystem.{ExtMem, SystemBusKey, WithInclusiveCache, InclusiveCacheKey} +import freechips.rocketchip.system.BaseConfig +import freechips.rocketchip.rocket.DCacheParams +import freechips.rocketchip.tile.{MaxHartIdBits, XLen} +import scala.math.{max, min} + +class WithTraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) + extends Config((site, here, up) => { + case TraceGenKey => 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 => if (params.size == 1) 1 else log2Ceil(params.size) +}) + +class TraceGenConfig extends Config( + new WithTraceGen(List.fill(2) { DCacheParams(nMSHRs = 0, nSets = 16, nWays = 2) }) ++ + new BaseConfig) + +class NonBlockingTraceGenConfig extends Config( + new WithTraceGen(List.fill(2) { DCacheParams(nMSHRs = 2, 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( + dcache = Some(dcp), + wordBits = site(XLen), + addrBits = 48, + addrBag = { + val sbp = site(SystemBusKey) + val l2p = site(InclusiveCacheKey) + val nSets = max(l2p.sets, dcp.nSets) + val nWays = max(l2p.ways, dcp.nWays) + val blockOffset = sbp.blockOffset + val nBeats = min(2, sbp.blockBeats) + val beatBytes = sbp.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 => if (params.size == 1) 1 else log2Ceil(params.size) +}) + +class NonBlockingTraceGenL2Config extends Config( + new WithL2TraceGen(List.fill(2)(DCacheParams(nMSHRs = 2, nSets = 16, nWays = 4))) ++ + new WithInclusiveCache ++ + new BaseConfig) diff --git a/generators/tracegen/src/main/scala/System.scala b/generators/tracegen/src/main/scala/System.scala new file mode 100644 index 00000000..57d048a3 --- /dev/null +++ b/generators/tracegen/src/main/scala/System.scala @@ -0,0 +1,43 @@ +package tracegen + +import chisel3._ +import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, BufferParams} +import freechips.rocketchip.groundtest.{DebugCombiner, TraceGenParams} +import freechips.rocketchip.subsystem._ + +case object TraceGenKey extends Field[Seq[TraceGenParams]] + +trait HasTraceGenTiles { this: BaseSubsystem => + val tiles = p(TraceGenKey).zipWithIndex.map { case (params, i) => + LazyModule(new TraceGenTile(i, params, p)) + } + + tiles.foreach { t => + sbus.fromTile(None, buffer = BufferParams.default) { t.masterNode } + } +} + +trait HasTraceGenTilesModuleImp extends LazyModuleImp { + val outer: HasTraceGenTiles + val success = IO(Output(Bool())) + + outer.tiles.zipWithIndex.map { case(t, i) => + t.module.constants.hartid := i.U + } + + val status = DebugCombiner(outer.tiles.map(_.module.status)) + success := status.finished +} + +class TraceGenSystem(implicit p: Parameters) extends BaseSubsystem + with HasTraceGenTiles + with HasHierarchicalBusTopology + with CanHaveMasterAXI4MemPort { + override lazy val module = new TraceGenSystemModuleImp(this) +} + +class TraceGenSystemModuleImp(outer: TraceGenSystem) + extends BaseSubsystemModuleImp(outer) + with HasTraceGenTilesModuleImp + with CanHaveMasterAXI4MemPortModuleImp diff --git a/generators/tracegen/src/main/scala/TestHarness.scala b/generators/tracegen/src/main/scala/TestHarness.scala new file mode 100644 index 00000000..93da430b --- /dev/null +++ b/generators/tracegen/src/main/scala/TestHarness.scala @@ -0,0 +1,27 @@ +package tracegen + +import chisel3._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy.LazyModule +import freechips.rocketchip.util.GeneratorApp + +class TestHarness(implicit p: Parameters) extends Module { + val io = IO(new Bundle { + val success = Output(Bool()) + }) + + val dut = Module(LazyModule(new TraceGenSystem).module) + io.success := dut.success + dut.connectSimAXIMem() +} + +object Generator extends GeneratorApp { + // specify the name that the generator outputs files as + val longName = names.topModuleProject + "." + names.topModuleClass + "." + names.configs + + // generate files + generateFirrtl + generateAnno + generateTestSuiteMakefrags + generateArtefacts +} diff --git a/generators/tracegen/src/main/scala/Tile.scala b/generators/tracegen/src/main/scala/Tile.scala new file mode 100644 index 00000000..1897224d --- /dev/null +++ b/generators/tracegen/src/main/scala/Tile.scala @@ -0,0 +1,53 @@ +package tracegen + +import chisel3._ +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.tilelink.{TLInwardNode, TLIdentityNode} +import freechips.rocketchip.interrupts._ + +class TraceGenTile(val id: Int, val params: TraceGenParams, q: Parameters) + extends BaseTile(params, SynchronousCrossing(), HartsWontDeduplicate(params), q) { + val dcache = params.dcache.map { dc => LazyModule( + if (dc.nMSHRs == 0) new DCache(hartId, crossing) + else new NonBlockingDCache(hartId)) + }.get + + 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 TraceGenTileModuleImp(this) +} + +class TraceGenTileModuleImp(outer: TraceGenTile) + extends BaseTileModuleImp(outer) { + val status = IO(new GroundTestStatus) + val halt_and_catch_fire = None + + val ptw = Module(new DummyPTW(1)) + ptw.io.requestors.head <> outer.dcache.module.io.ptw + + val tracegen = Module(new TraceGenerator(outer.params)) + tracegen.io.hartid := constants.hartid + + val dcacheIF = Module(new SimpleHellaCacheIF()) + dcacheIF.io.requestor <> tracegen.io.mem + outer.dcache.module.io.cpu <> dcacheIF.io.cache + + status.finished := tracegen.io.finished + status.timeout.valid := tracegen.io.timeout + status.timeout.bits := 0.U + status.error.valid := false.B + + assert(!tracegen.io.timeout, s"TraceGen tile ${outer.id}: request timed out") +} diff --git a/variables.mk b/variables.mk index ca0f8fc9..2243f320 100644 --- a/variables.mk +++ b/variables.mk @@ -38,6 +38,17 @@ ifeq ($(SUB_PROJECT),example) TB ?= TestDriver TOP ?= BoomRocketTop endif +ifeq ($(SUB_PROJECT),tracegen) + SBT_PROJECT ?= tracegen + MODEL ?= TestHarness + VLOG_MODEL ?= $(MODEL) + MODEL_PACKAGE ?= $(SBT_PROJECT) + CONFIG ?= TraceGenConfig + CONFIG_PACKAGE ?= $(SBT_PROJECT) + GENERATOR_PACKAGE ?= $(SBT_PROJECT) + TB ?= TestDriver + TOP ?= TraceGenSystem +endif # for Rocket-chip developers ifeq ($(SUB_PROJECT),rocketchip) SBT_PROJECT ?= rocketchip From 0e8fb52f8d9c6eaa6ab4bcb0652b489653ca9174 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 17 Jul 2019 13:10:09 -0700 Subject: [PATCH 29/91] add check-tracegen.sh script --- scripts/check-tracegen.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100755 scripts/check-tracegen.sh diff --git a/scripts/check-tracegen.sh b/scripts/check-tracegen.sh new file mode 100755 index 00000000..6462613c --- /dev/null +++ b/scripts/check-tracegen.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +SCRIPT_DIR=$(dirname $0) +AXE_DIR=$(realpath ${SCRIPT_DIR}/../../axe) +ROCKET_DIR=$(realpath ${SCRIPT_DIR}/../generators/rocket-chip) + +TO_AXE=${ROCKET_DIR}/scripts/toaxe.py +AXE=${AXE_DIR}/src/axe +AXE_SHRINK=${AXE_DIR}/src/axe-shrink.py + +PATH=$PATH:${AXE_DIR}/src + +grep '.*:.*#.*@' $1 > /tmp/clean-trace.txt +$TO_AXE /tmp/clean-trace.txt > /tmp/trace.axe +result=$($AXE check wmo /tmp/trace.axe) + +if [ $result != "OK" ]; then + $AXE_SHRINK wmo /tmp/trace.axe +else + echo "OK" +fi From a2171bc7b85e0589379336b819a1f6b8b91df2c3 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 28 Aug 2019 20:38:44 -0700 Subject: [PATCH 30/91] find all scala source files instead of searching individual project directories --- common.mk | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/common.mk b/common.mk index 16208e82..764495f3 100644 --- a/common.mk +++ b/common.mk @@ -6,11 +6,10 @@ SHELL=/bin/bash ######################################################################################### # variables to get all *.scala files ######################################################################################### -lookup_scala_srcs = $(shell find -L $(1)/ -iname "*.scala" 2> /dev/null) +lookup_scala_srcs = $(shell find -L $(1)/ -name target -prune -o -iname "*.scala" -print 2> /dev/null) -PACKAGES=$(addprefix generators/, rocket-chip testchipip boom hwacha sifive-blocks sifive-cache example) \ - $(addprefix sims/firesim/sim/, . firesim-lib midas midas/targetutils) -SCALA_SOURCES=$(foreach pkg,$(PACKAGES),$(call lookup_scala_srcs,$(base_dir)/$(pkg)/src/main/scala)) +SOURCE_DIRS=$(addprefix $(base_dir)/,generators sims/firesim/sim) +SCALA_SOURCES=$(call lookup_scala_srcs,$(SOURCE_DIRS)) ######################################################################################### # rocket and testchipip classes From c33c6a2985dc41d1a97c1256f2723cef289bafce Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Fri, 30 Aug 2019 11:37:20 -0700 Subject: [PATCH 31/91] get rid of now-defunct documention --- docs/Customization/Adding-An-Accelerator.rst | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/Customization/Adding-An-Accelerator.rst b/docs/Customization/Adding-An-Accelerator.rst index 0b688ea6..90a74733 100644 --- a/docs/Customization/Adding-An-Accelerator.rst +++ b/docs/Customization/Adding-An-Accelerator.rst @@ -61,15 +61,6 @@ the ``example`` project, change the final line in build.sbt to the following. lazy val example = (project in file(".")).settings(commonSettings).dependsOn(testchipip, yourproject) -Finally, add ``yourproject`` to the ``PACKAGES`` variable in the ``common.mk`` file in the Chipyard top level. -This will allow make to detect that your source files have changed when building the Verilog/FIRRTL files. - -.. code-block:: shell - - PACKAGES=$(addprefix generators/, rocket-chip testchipip boom hwacha sifive-blocks sifive-cache example yourproject) \ - $(addprefix sims/firesim/sim/, . firesim-lib midas midas/targetutils) - - MMIO Peripheral ------------------ From f34a6fc5233bbc21900b01c65ac4b46a213d139d Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 30 Aug 2019 01:02:51 -0700 Subject: [PATCH 32/91] reallow you to do -j for make | parallel ci runs --- .circleci/build-verilator.sh | 2 +- .circleci/do-rtl-build.sh | 2 +- .circleci/run-tests.sh | 6 +++--- common.mk | 16 ++++++++++++---- sims/verilator/Makefile | 5 ++--- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.circleci/build-verilator.sh b/.circleci/build-verilator.sh index acd038fb..934025e3 100755 --- a/.circleci/build-verilator.sh +++ b/.circleci/build-verilator.sh @@ -23,7 +23,7 @@ if [ ! -d "$LOCAL_VERILATOR_DIR" ]; then run "mkdir -p $REMOTE_CHIPYARD_DIR" copy $LOCAL_CHIPYARD_DIR/ $SERVER:$REMOTE_CHIPYARD_DIR - run "make -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR verilator_install" + run "make -j8 -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR verilator_install" # copy so that circleci can cache mkdir -p $LOCAL_CHIPYARD_DIR diff --git a/.circleci/do-rtl-build.sh b/.circleci/do-rtl-build.sh index 00dc7290..68dbd7c8 100755 --- a/.circleci/do-rtl-build.sh +++ b/.circleci/do-rtl-build.sh @@ -41,7 +41,7 @@ fi # enter the verilator directory and build the specific config on remote server run "make -C $REMOTE_SIM_DIR clean" -run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; make -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR JAVA_ARGS=\"-Xmx8G -Xss8M\" ${mapping[$1]}" +run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; make -j8 -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR JAVA_ARGS=\"-Xmx8G -Xss8M\" ${mapping[$1]}" run "rm -rf $REMOTE_CHIPYARD_DIR/project" # copy back the final build diff --git a/.circleci/run-tests.sh b/.circleci/run-tests.sh index 99fd42dd..8cc11e10 100755 --- a/.circleci/run-tests.sh +++ b/.circleci/run-tests.sh @@ -12,11 +12,11 @@ source $SCRIPT_DIR/defaults.sh export VERILATOR_ROOT=$LOCAL_VERILATOR_DIR/install/share/verilator run_bmark () { - make run-bmark-tests-fast -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR $@ + make run-bmark-tests-fast -j8 -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR $@ } run_asm () { - make run-asm-tests-fast -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR $@ + make run-asm-tests-fast -j8 -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR $@ } run_both () { @@ -44,7 +44,7 @@ case $1 in export RISCV=$LOCAL_ESP_DIR export LD_LIBRARY_PATH=$LOCAL_ESP_DIR/lib export PATH=$RISCV/bin:$PATH - make run-rv64uv-p-asm-tests -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR ${mapping[$1]} + make run-rv64uv-p-asm-tests -j8 -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR ${mapping[$1]} ;; *) echo "No set of tests for $1. Did you spell it right?" diff --git a/common.mk b/common.mk index 764495f3..0be75fd6 100644 --- a/common.mk +++ b/common.mk @@ -38,7 +38,9 @@ $(sim_files): $(call lookup_scala_srcs,$(base_dir)/generators/utilities/src/main ######################################################################################### # create firrtl file rule and variables ######################################################################################### -$(FIRRTL_FILE) $(ANNO_FILE): $(SCALA_SOURCES) $(sim_files) +.INTERMEDIATE: generator_temp +$(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)" @@ -51,16 +53,22 @@ HARNESS_CONF_FLAGS = -thconf $(HARNESS_SMEMS_CONF) TOP_TARGETS = $(TOP_FILE) $(TOP_SMEMS_CONF) $(TOP_ANNO) $(TOP_FIR) $(sim_top_blackboxes) HARNESS_TARGETS = $(HARNESS_FILE) $(HARNESS_SMEMS_CONF) $(HARNESS_ANNO) $(HARNESS_FIR) $(sim_harness_blackboxes) -$(TOP_TARGETS) $(HARNESS_TARGETS): $(FIRRTL_FILE) $(ANNO_FILE) +.INTERMEDIATE: firrtl_temp +$(TOP_TARGETS) $(HARNESS_TARGETS): firrtl_temp +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)" # This file is for simulation only. VLSI flows should replace this file with one containing hard SRAMs MACROCOMPILER_MODE ?= --mode synflops -$(TOP_SMEMS_FILE) $(TOP_SMEMS_FIR): $(TOP_SMEMS_CONF) +.INTERMEDIATE: top_macro_temp +$(TOP_SMEMS_FILE) $(TOP_SMEMS_FIR): top_macro_temp +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 -$(HARNESS_SMEMS_FILE) $(HARNESS_SMEMS_FIR): $(HARNESS_SMEMS_CONF) +.INTERMEDIATE: harness_macro_temp +$(HARNESS_SMEMS_FILE) $(HARNESS_SMEMS_FIR): harness_macro_temp +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)" ######################################################################################## diff --git a/sims/verilator/Makefile b/sims/verilator/Makefile index 3763f627..ae27afdf 100644 --- a/sims/verilator/Makefile +++ b/sims/verilator/Makefile @@ -97,12 +97,11 @@ $(model_mk_debug): $(sim_vsrcs) $(sim_common_files) $(INSTALLED_VERILATOR) ######################################################################################### # invoke make to make verilator sim rules ######################################################################################### -VERILATOR_MAKEFLAGS=-j8 $(sim): $(model_mk) - $(MAKE) $(VERILATOR_MAKEFLAGS) VM_PARALLEL_BUILDS=1 -C $(model_dir) -f V$(VLOG_MODEL).mk + $(MAKE) VM_PARALLEL_BUILDS=1 -C $(model_dir) -f V$(VLOG_MODEL).mk $(sim_debug): $(model_mk_debug) - $(MAKE) $(VERILATOR_MAKEFLAGS) VM_PARALLEL_BUILDS=1 -C $(model_dir_debug) -f V$(VLOG_MODEL).mk + $(MAKE) VM_PARALLEL_BUILDS=1 -C $(model_dir_debug) -f V$(VLOG_MODEL).mk ######################################################################################### # create a verilator vpd rule From 64d2783b5f0a3d89cb31143fdd5863f0146ec40d Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 30 Aug 2019 23:18:17 -0700 Subject: [PATCH 33/91] use variable to control make parallelism in ci --- .circleci/build-verilator.sh | 2 +- .circleci/defaults.sh | 3 +++ .circleci/do-rtl-build.sh | 2 +- .circleci/run-tests.sh | 6 +++--- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.circleci/build-verilator.sh b/.circleci/build-verilator.sh index 934025e3..a6780d1c 100755 --- a/.circleci/build-verilator.sh +++ b/.circleci/build-verilator.sh @@ -23,7 +23,7 @@ if [ ! -d "$LOCAL_VERILATOR_DIR" ]; then run "mkdir -p $REMOTE_CHIPYARD_DIR" copy $LOCAL_CHIPYARD_DIR/ $SERVER:$REMOTE_CHIPYARD_DIR - run "make -j8 -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR verilator_install" + run "make -j$NPROC -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR verilator_install" # copy so that circleci can cache mkdir -p $LOCAL_CHIPYARD_DIR diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index fb7a3571..66cf3b3d 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -17,6 +17,9 @@ clean () { run "rm -rf $REMOTE_WORK_DIR" } +# make parallelism +NPROC=8 + # remote variables REMOTE_WORK_DIR=$CI_DIR/$CIRCLE_PROJECT_REPONAME-$CIRCLE_BRANCH-$CIRCLE_SHA1-$CIRCLE_JOB REMOTE_RISCV_DIR=$REMOTE_WORK_DIR/riscv-tools-install diff --git a/.circleci/do-rtl-build.sh b/.circleci/do-rtl-build.sh index 68dbd7c8..c4eb04ab 100755 --- a/.circleci/do-rtl-build.sh +++ b/.circleci/do-rtl-build.sh @@ -41,7 +41,7 @@ fi # enter the verilator directory and build the specific config on remote server run "make -C $REMOTE_SIM_DIR clean" -run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; make -j8 -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR JAVA_ARGS=\"-Xmx8G -Xss8M\" ${mapping[$1]}" +run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; make -j$NPROC -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR JAVA_ARGS=\"-Xmx8G -Xss8M\" ${mapping[$1]}" run "rm -rf $REMOTE_CHIPYARD_DIR/project" # copy back the final build diff --git a/.circleci/run-tests.sh b/.circleci/run-tests.sh index 8cc11e10..4a6d9e7b 100755 --- a/.circleci/run-tests.sh +++ b/.circleci/run-tests.sh @@ -12,11 +12,11 @@ source $SCRIPT_DIR/defaults.sh export VERILATOR_ROOT=$LOCAL_VERILATOR_DIR/install/share/verilator run_bmark () { - make run-bmark-tests-fast -j8 -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR $@ + make run-bmark-tests-fast -j$NPROC -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR $@ } run_asm () { - make run-asm-tests-fast -j8 -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR $@ + make run-asm-tests-fast -j$NPROC -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR $@ } run_both () { @@ -44,7 +44,7 @@ case $1 in export RISCV=$LOCAL_ESP_DIR export LD_LIBRARY_PATH=$LOCAL_ESP_DIR/lib export PATH=$RISCV/bin:$PATH - make run-rv64uv-p-asm-tests -j8 -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR ${mapping[$1]} + make run-rv64uv-p-asm-tests -j$NPROC -C $LOCAL_SIM_DIR VERILATOR_INSTALL_DIR=$LOCAL_VERILATOR_DIR ${mapping[$1]} ;; *) echo "No set of tests for $1. Did you spell it right?" From 40a94dd08e2ae2f8d54b06430907723e0e43a4bf Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Sat, 31 Aug 2019 01:14:39 -0700 Subject: [PATCH 34/91] scripts: Parse options with getopts builtin --- scripts/build-toolchains.sh | 66 ++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index e743afe4..03ddc8fa 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -12,12 +12,16 @@ RDIR=$(pwd) PRECOMPILED_REPO_HASH=56a40961c98db5e8f904f15dc6efd0870bfefd9e -function usage -{ - echo "usage: ./scripts/build-toolchains.sh [riscv-tools] [esp-tools] [ec2fast | --ec2fast] " +usage() { + echo "usage: ${0} [riscv-tools | esp-tools | ec2fast]" echo " riscv: if set, builds the riscv toolchain (this is also the default)" echo " hwacha: if set, builds esp-tools toolchain" echo " ec2fast: if set, pulls in a pre-compiled RISC-V toolchain for an EC2 manager instance" + exit "$1" +} + +error() { + echo "${0##*/}: ${1}" >&2 } #taken from riscv-tools to check for open-ocd autoconf versions @@ -28,42 +32,38 @@ check_version() { ) } -if [ "$1" == "--help" -o "$1" == "-h" -o "$1" == "-H" ]; then - usage - exit 3 -fi - TOOLCHAIN="riscv-tools" EC2FASTINSTALL="false" FASTINSTALL="false" -while test $# -gt 0 -do - case "$1" in - riscv-tools) - TOOLCHAIN="riscv-tools" - ;; - esp-tools) - TOOLCHAIN="esp-tools" - ;; - ec2fast | --ec2fast) # I don't want to break this api - EC2FASTINSTALL=true - ;; - -h | -H | --help) - usage - exit 3 - ;; - --*) echo "ERROR: bad option $1" - usage - exit 1 - ;; - *) echo "ERROR: bad argument $1" - usage - exit 2 - ;; + +while getopts 'hH-:' opt ; do + case $opt in + h|H) + usage 3 ;; + -) + case $OPTARG in + help) + usage 3 ;; + ec2fast) # Preserve compatibility + EC2FASTINSTALL=true ;; + *) + error "invalid option: --${OPTARG}" + usage 1 ;; + esac ;; + *) + error "invalid option: -${opt}" + usage 1 ;; esac - shift done +shift $((OPTIND - 1)) + +if [ "$1" = ec2fast ] ; then + EC2FASTINSTALL=true +elif [ -z "$1" ] ; then + TOOLCHAIN="$1" +fi + if [ "$EC2FASTINSTALL" = "true" ]; then if [ "$TOOLCHAIN" = "riscv-tools" ]; then From 10b708d1732d5c2832dd06991118bec91738ff59 Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Sat, 31 Aug 2019 01:25:56 -0700 Subject: [PATCH 35/91] scripts: Ensure non-zero exit code on error --- scripts/build-toolchains.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index 03ddc8fa..c1d1da62 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -82,12 +82,12 @@ if [ "$EC2FASTINSTALL" = "true" ]; then FASTINSTALL=true echo "Using fast pre-compiled install for riscv-tools" else - echo "Error: hash of precompiled toolchain doesn't match the riscv-tools submodule hash." - exit + error 'error: hash of precompiled toolchain does not match the riscv-tools submodule hash' + exit -1 fi else - echo "Error: No precompiled toolchain for esp-tools or other non-native riscv-tools." - exit + error "error: unsupported precompiled toolchain: ${TOOLCHAIN}" + exit -1 fi fi From 2c2f5a76e3f1648b77c56a68b803d8b096770697 Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Sat, 31 Aug 2019 01:52:51 -0700 Subject: [PATCH 36/91] scripts: Fix quoting to prevent unintended word splitting --- scripts/build-static-libfesvr.sh | 2 +- scripts/build-toolchains.sh | 40 +++++++++++------------ scripts/check-tracegen.sh | 10 +++--- scripts/firesim-setup.sh | 6 ++-- scripts/init-submodules-no-riscv-tools.sh | 4 +-- scripts/init-vlsi.sh | 4 +-- 6 files changed, 32 insertions(+), 34 deletions(-) diff --git a/scripts/build-static-libfesvr.sh b/scripts/build-static-libfesvr.sh index 360028ad..96724bd6 100755 --- a/scripts/build-static-libfesvr.sh +++ b/scripts/build-static-libfesvr.sh @@ -13,5 +13,5 @@ set -e objs=$(head -n 1 <(make -f <( echo -e 'include Makefile\n$(info $(value fesvr_objs))') -n)) ar rcs -o libfesvr.a $objs -cp -f libfesvr.a $RISCV/lib +cp -f libfesvr.a "${RISCV}/lib" diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index c1d1da62..8e0d40e7 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -26,10 +26,10 @@ error() { #taken from riscv-tools to check for open-ocd autoconf versions check_version() { - $1 --version | awk "NR==1 {if (\$NF>$2) {exit 0} exit 1}" || ( - echo $3 requires at least version $2 of $1. Aborting. + "$1" --version | awk "NR==1 {if (\$NF>$2) {exit 0} exit 1}" || { + error "${3} requires at least ${1} version ${2}" exit 1 - ) + } } TOOLCHAIN="riscv-tools" @@ -60,22 +60,22 @@ shift $((OPTIND - 1)) if [ "$1" = ec2fast ] ; then EC2FASTINSTALL=true -elif [ -z "$1" ] ; then +elif [ -n "$1" ] ; then TOOLCHAIN="$1" fi if [ "$EC2FASTINSTALL" = "true" ]; then if [ "$TOOLCHAIN" = "riscv-tools" ]; then - cd $RDIR + cd "$RDIR" git clone https://github.com/firesim/firesim-riscv-tools-prebuilt.git cd firesim-riscv-tools-prebuilt - git checkout $PRECOMPILED_REPO_HASH + git checkout "$PRECOMPILED_REPO_HASH" PREBUILTHASH="$(cat HASH)" - git -C $CHIPYARD_DIR submodule update --init toolchains/$TOOLCHAIN + git -C "${CHIPYARD_DIR}" submodule update --init "toolchains/${TOOLCHAIN}" cd "$CHIPYARD_DIR/toolchains/$TOOLCHAIN" GITHASH="$(git rev-parse HEAD)" - cd $RDIR + cd "$RDIR" echo "prebuilt hash: $PREBUILTHASH" echo "git hash: $GITHASH" if [[ $PREBUILTHASH == $GITHASH && "$EC2FASTINSTALL" == "true" ]]; then @@ -104,28 +104,28 @@ if [ "$FASTINSTALL" = true ]; then mv distrib "$RISCV" # copy HASH in case user wants it later cp HASH "$RISCV" - cd $RDIR + cd "$RDIR" rm -rf firesim-riscv-tools-prebuilt else mkdir -p "$RISCV" - git -C $CHIPYARD_DIR submodule update --init --recursive toolchains/$TOOLCHAIN #--jobs 8 + git -C "${CHIPYARD_DIR}" submodule update --init --recursive "toolchains/${TOOLCHAIN}" #--jobs 8 cd "$CHIPYARD_DIR/toolchains/$TOOLCHAIN" export MAKEFLAGS="-j16" #build the actual toolchain #./build.sh source build.common echo "Starting RISC-V Toolchain build process" - build_project riscv-fesvr --prefix=$RISCV - build_project riscv-isa-sim --prefix=$RISCV --with-fesvr=$RISCV - build_project riscv-gnu-toolchain --prefix=$RISCV - CC= CXX= build_project riscv-pk --prefix=$RISCV --host=riscv64-unknown-elf - build_project riscv-tests --prefix=$RISCV/riscv64-unknown-elf + build_project riscv-fesvr --prefix="${RISCV}" + build_project riscv-isa-sim --prefix="${RISCV}" --with-fesvr="${RISCV}" + build_project riscv-gnu-toolchain --prefix="${RISCV}" + CC= CXX= build_project riscv-pk --prefix="${RISCV}" --host=riscv64-unknown-elf + build_project riscv-tests --prefix="${RISCV}/riscv64-unknown-elf" echo -e "\\nRISC-V Toolchain installation completed!" # build static libfesvr library for linking into firesim driver (or others) cd riscv-fesvr/build - $CHIPYARD_DIR/scripts/build-static-libfesvr.sh - cd $RDIR + "${CHIPYARD_DIR}/scripts/build-static-libfesvr.sh" + cd "$RDIR" # build linux toolchain cd "$CHIPYARD_DIR/toolchains/$TOOLCHAIN/riscv-gnu-toolchain/build" make -j16 linux @@ -133,7 +133,7 @@ else fi -cd $RDIR +cd "$RDIR" echo "export CHIPYARD_TOOLCHAIN_SOURCED=1" > env.sh echo "export RISCV=$RISCV" >> env.sh @@ -153,8 +153,8 @@ if [ "$FASTINSTALL" = "false" ]; then cd "$CHIPYARD_DIR/toolchains/$TOOLCHAIN" check_version automake 1.14 "OpenOCD build" check_version autoconf 2.64 "OpenOCD build" - build_project riscv-openocd --prefix=$RISCV --enable-remote-bitbang --enable-jtag_vpi --disable-werror + build_project riscv-openocd --prefix="${RISCV}" --enable-remote-bitbang --enable-jtag_vpi --disable-werror echo -e "\\nRISC-V OpenOCD installation completed!" - cd $RDIR + cd "$RDIR" fi fi diff --git a/scripts/check-tracegen.sh b/scripts/check-tracegen.sh index 6462613c..bc82f572 100755 --- a/scripts/check-tracegen.sh +++ b/scripts/check-tracegen.sh @@ -13,11 +13,11 @@ AXE_SHRINK=${AXE_DIR}/src/axe-shrink.py PATH=$PATH:${AXE_DIR}/src grep '.*:.*#.*@' $1 > /tmp/clean-trace.txt -$TO_AXE /tmp/clean-trace.txt > /tmp/trace.axe -result=$($AXE check wmo /tmp/trace.axe) +"$TO_AXE" /tmp/clean-trace.txt > /tmp/trace.axe +result=$("$AXE" check wmo /tmp/trace.axe) -if [ $result != "OK" ]; then - $AXE_SHRINK wmo /tmp/trace.axe +if [ "$result" != OK ]; then + "$AXE_SHRINK" wmo /tmp/trace.axe else - echo "OK" + echo OK fi diff --git a/scripts/firesim-setup.sh b/scripts/firesim-setup.sh index 302294bf..0787fd3c 100755 --- a/scripts/firesim-setup.sh +++ b/scripts/firesim-setup.sh @@ -8,11 +8,11 @@ set -o pipefail RDIR=$(pwd) scripts_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -cd $scripts_dir/.. +cd "${scripts_dir}/.." # Reenable the FireSim submodule git config --unset submodule.sims/firesim.update || true git submodule update --init sims/firesim cd sims/firesim -./build-setup.sh $@ --library -cd $RDIR +./build-setup.sh "$@" --library +cd "$RDIR" diff --git a/scripts/init-submodules-no-riscv-tools.sh b/scripts/init-submodules-no-riscv-tools.sh index 3a95f5c6..8cd6ced3 100755 --- a/scripts/init-submodules-no-riscv-tools.sh +++ b/scripts/init-submodules-no-riscv-tools.sh @@ -28,9 +28,9 @@ git config --unset submodule.vlsi/hammer-cad-plugins.update # 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 -cd $scripts_dir/../sims/ +cd "${scripts_dir}/../sims" git submodule update --init firesim cd firesim/sim git submodule update --init midas -cd $RDIR +cd "$RDIR" git config submodule.sims/firesim.update none diff --git a/scripts/init-vlsi.sh b/scripts/init-vlsi.sh index 294f8628..89f9ac56 100755 --- a/scripts/init-vlsi.sh +++ b/scripts/init-vlsi.sh @@ -3,11 +3,9 @@ set -e set -o pipefail - - # Initialize HAMMER and CAD-plugins git submodule update --init --recursive vlsi/hammer git submodule update --init --recursive vlsi/hammer-cad-plugins # Initialize HAMMER tech plugin -git submodule update --init --recursive vlsi/hammer-$1-plugin \ No newline at end of file +git submodule update --init --recursive vlsi/hammer-"$1"-plugin From 9e9e7dd442ade2a0988a5ce03116928b0d79ce97 Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Sat, 31 Aug 2019 02:00:48 -0700 Subject: [PATCH 37/91] scripts: Fix latent issues with env.sh * Ensure shell metacharacters are quoted in RISCV variable assignment. * Avoid unnecessary expansion of $RISCV and $LD_LIBRARY_PATH at generation time. * Remove undefined usage of $DTCversion. * Simplify output redirection. --- scripts/build-toolchains.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index 8e0d40e7..6d466ad7 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -135,13 +135,14 @@ fi cd "$RDIR" -echo "export CHIPYARD_TOOLCHAIN_SOURCED=1" > env.sh -echo "export RISCV=$RISCV" >> env.sh -echo "export PATH=$RISCV/bin:$RDIR/$DTCversion:\$PATH" >> env.sh -echo "export LD_LIBRARY_PATH=$RISCV/lib\${LD_LIBRARY_PATH:+":${LD_LIBRARY_PATH}"}" >> env.sh +{ + echo "export CHIPYARD_TOOLCHAIN_SOURCED=1" + echo "export RISCV=$(printf '%q' "$RISCV")" + echo "export PATH=\${RISCV}/bin:\${PATH}" + echo "export LD_LIBRARY_PATH=\${RISCV}/lib\${LD_LIBRARY_PATH:+":\${LD_LIBRARY_PATH}"}" +} > env.sh echo "Toolchain Build Complete!" - if [ "$FASTINSTALL" = "false" ]; then # commands that can't run on EC2 (specifically, OpenOCD because of autoconf version_ # see if the instance info page exists. if not, we are not on ec2. From cff1f6b11e398be0748c944c5f96268ee2f782ce Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Sat, 31 Aug 2019 03:11:46 -0700 Subject: [PATCH 38/91] scripts: Eliminate unnecessary process substitution --- scripts/build-static-libfesvr.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/build-static-libfesvr.sh b/scripts/build-static-libfesvr.sh index 96724bd6..d5b7f896 100755 --- a/scripts/build-static-libfesvr.sh +++ b/scripts/build-static-libfesvr.sh @@ -11,7 +11,11 @@ fi set -e -objs=$(head -n 1 <(make -f <( echo -e 'include Makefile\n$(info $(value fesvr_objs))') -n)) +objs=$(make -n -f <( + echo 'include Makefile' + echo '$(info $(value fesvr_objs))' + ) | head -n 1) + ar rcs -o libfesvr.a $objs cp -f libfesvr.a "${RISCV}/lib" From 4963792e98eafc3a8c086da85c2e0904b503c43c Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Sat, 31 Aug 2019 14:51:14 -0700 Subject: [PATCH 39/91] scripts: Scale number of make jobs by hardware thread count If the hardware thread/core count cannot be determined successfully, avoid setting the '-j' option for make. --- scripts/build-toolchains.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/build-toolchains.sh b/scripts/build-toolchains.sh index 6d466ad7..76680f79 100755 --- a/scripts/build-toolchains.sh +++ b/scripts/build-toolchains.sh @@ -110,7 +110,18 @@ else mkdir -p "$RISCV" git -C "${CHIPYARD_DIR}" submodule update --init --recursive "toolchains/${TOOLCHAIN}" #--jobs 8 cd "$CHIPYARD_DIR/toolchains/$TOOLCHAIN" - export MAKEFLAGS="-j16" + + # Scale number of parallel make jobs by hardware thread count + ncpu="$(getconf _NPROCESSORS_ONLN || # GNU + getconf NPROCESSORS_ONLN || # *BSD, Solaris + nproc --all || # Linux + sysctl -n hw.ncpu || # *BSD, OS X + :)" 2>/dev/null + case ${ncpu} in + ''|*[^0-9]*) ;; # Ignore non-integer values + *) export MAKEFLAGS="-j ${ncpu}" ;; + esac + #build the actual toolchain #./build.sh source build.common @@ -128,7 +139,7 @@ else cd "$RDIR" # build linux toolchain cd "$CHIPYARD_DIR/toolchains/$TOOLCHAIN/riscv-gnu-toolchain/build" - make -j16 linux + make linux echo -e "\\nRISC-V Linux GNU Toolchain installation completed!" fi From 8e343dee046e16813e5c267b7b6154e64628b9fb Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Sun, 1 Sep 2019 07:11:52 -0700 Subject: [PATCH 40/91] Fix sha3 build-system dependency --- .gitmodules | 2 +- common.mk | 2 +- generators/{rocc-template => sha3} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename generators/{rocc-template => sha3} (100%) diff --git a/.gitmodules b/.gitmodules index fc31b672..cad55a67 100644 --- a/.gitmodules +++ b/.gitmodules @@ -56,5 +56,5 @@ path = tools/treadle url = https://github.com/freechipsproject/treadle.git [submodule "generators/rocc-template"] - path = generators/rocc-template + path = generators/sha3 url = https://github.com/ucb-bar/rocc-template.git diff --git a/common.mk b/common.mk index 3c333c68..103e5407 100644 --- a/common.mk +++ b/common.mk @@ -8,7 +8,7 @@ SHELL=/bin/bash ######################################################################################### lookup_scala_srcs = $(shell find -L $(1)/ -iname "*.scala" 2> /dev/null) -PACKAGES=$(addprefix generators/, rocket-chip testchipip boom hwacha sifive-blocks sifive-cache example) \ +PACKAGES=$(addprefix generators/, rocket-chip testchipip boom hwacha sifive-blocks sifive-cache rocc-template example) \ $(addprefix sims/firesim/sim/, . firesim-lib midas midas/targetutils) SCALA_SOURCES=$(foreach pkg,$(PACKAGES),$(call lookup_scala_srcs,$(base_dir)/$(pkg)/src/main/scala)) diff --git a/generators/rocc-template b/generators/sha3 similarity index 100% rename from generators/rocc-template rename to generators/sha3 From f3026af8b13c0702f39aaed8777cbb11c470b5d4 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 2 Sep 2019 09:22:10 -0700 Subject: [PATCH 41/91] get rid of redundant regression test lists --- common.mk | 36 ------------------- .../firechip/src/main/scala/Generator.scala | 36 ------------------- 2 files changed, 72 deletions(-) diff --git a/common.mk b/common.mk index 764495f3..f8c117dd 100644 --- a/common.mk +++ b/common.mk @@ -115,39 +115,3 @@ $(output_dir)/%.out: $(output_dir)/% $(sim) ifneq ($(filter run% %.run %.out %.vpd %.vcd,$(MAKECMDGOALS)),) -include $(build_dir)/$(long_name).d endif - -######################################################################################### -# default regression tests variables and rules -# TODO: Remove in favor of each project having its own regression tests? -######################################################################################### -regression-tests = \ - rv64ud-v-fcvt \ - rv64ud-p-fdiv \ - rv64ud-v-fadd \ - rv64uf-v-fadd \ - rv64um-v-mul \ - rv64mi-p-breakpoint \ - rv64uc-v-rvc \ - rv64ud-v-structural \ - rv64si-p-wfi \ - rv64um-v-divw \ - rv64ua-v-lrsc \ - rv64ui-v-fence_i \ - rv64ud-v-fcvt_w \ - rv64uf-v-fmin \ - rv64ui-v-sb \ - rv64ua-v-amomax_d \ - rv64ud-v-move \ - rv64ud-v-fclass \ - rv64ua-v-amoand_d \ - rv64ua-v-amoxor_d \ - rv64si-p-sbreak \ - rv64ud-v-fmadd \ - rv64uf-v-ldst \ - rv64um-v-mulh \ - rv64si-p-dirty - -.PHONY: run-regression-tests run-regression-tests-fast run-regression-tests-debug -run-regression-tests: $(addprefix $(output_dir)/,$(addsuffix .out,$(regression-tests))) -run-regression-tests-fast: $(addprefix $(output_dir)/,$(addsuffix .run,$(regression-tests))) -run-regression-tests-debug: $(addprefix $(output_dir)/,$(addsuffix .vpd,$(regression-tests))) diff --git a/generators/firechip/src/main/scala/Generator.scala b/generators/firechip/src/main/scala/Generator.scala index 7f8c796a..169cbe1f 100644 --- a/generators/firechip/src/main/scala/Generator.scala +++ b/generators/firechip/src/main/scala/Generator.scala @@ -21,42 +21,6 @@ import firesim.util.{GeneratorArgs, HasTargetAgnosticUtilites, HasFireSimGenerat import utilities.TestSuiteHelper trait HasTestSuites { - val rv64RegrTestNames = collection.mutable.LinkedHashSet( - "rv64ud-v-fcvt", - "rv64ud-p-fdiv", - "rv64ud-v-fadd", - "rv64uf-v-fadd", - "rv64um-v-mul", - "rv64mi-p-breakpoint", - "rv64uc-v-rvc", - "rv64ud-v-structural", - "rv64si-p-wfi", - "rv64um-v-divw", - "rv64ua-v-lrsc", - "rv64ui-v-fence_i", - "rv64ud-v-fcvt_w", - "rv64uf-v-fmin", - "rv64ui-v-sb", - "rv64ua-v-amomax_d", - "rv64ud-v-move", - "rv64ud-v-fclass", - "rv64ua-v-amoand_d", - "rv64ua-v-amoxor_d", - "rv64si-p-sbreak", - "rv64ud-v-fmadd", - "rv64uf-v-ldst", - "rv64um-v-mulh", - "rv64si-p-dirty") - - val rv32RegrTestNames = collection.mutable.LinkedHashSet( - "rv32mi-p-ma_addr", - "rv32mi-p-csr", - "rv32ui-p-sh", - "rv32ui-p-lh", - "rv32uc-p-rvc", - "rv32mi-p-sbreak", - "rv32ui-p-sll") - def addTestSuites(targetName: String, params: Parameters) { TestSuiteHelper.addRocketTestSuites(params) TestSuiteHelper.addBoomTestSuites(params) From 5bda60063a2992df9832237faa11416ba13d8d74 Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Thu, 5 Sep 2019 00:14:21 +0000 Subject: [PATCH 42/91] [firesim] Initial Golden Gate support --- .../firechip/src/main/scala/SimConfigs.scala | 4 +++ .../src/main/scala/TargetMixins.scala | 27 ++++++++++++++++++- .../firechip/src/main/scala/Targets.scala | 4 +++ .../src/test/scala/ScalaTestSuite.scala | 7 ++--- sims/firesim | 2 +- 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/generators/firechip/src/main/scala/SimConfigs.scala b/generators/firechip/src/main/scala/SimConfigs.scala index 1118fe07..937c2877 100644 --- a/generators/firechip/src/main/scala/SimConfigs.scala +++ b/generators/firechip/src/main/scala/SimConfigs.scala @@ -52,3 +52,7 @@ class FireSimDDR3FRFCFSLLC4MB3ClockDivConfig extends Config( new FRFCFS16GBQuadRankLLC4MB3Div ++ new FireSimConfig) +class Midas2Config extends Config( + new WithMultiCycleRamModels ++ + new FireSimConfig) + diff --git a/generators/firechip/src/main/scala/TargetMixins.scala b/generators/firechip/src/main/scala/TargetMixins.scala index 199a22cc..76dc224e 100644 --- a/generators/firechip/src/main/scala/TargetMixins.scala +++ b/generators/firechip/src/main/scala/TargetMixins.scala @@ -1,6 +1,7 @@ package firesim.firesim import chisel3._ +import chisel3.experimental.annotate import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ @@ -12,7 +13,7 @@ import freechips.rocketchip.rocket.TracedInstruction import firesim.endpoints.{TraceOutputTop, DeclockedTracedInstruction} import midas.models.AXI4BundleWithEdge -import midas.targetutils.ExcludeInstanceAsserts +import midas.targetutils.{ExcludeInstanceAsserts, MemModelAnnotation} /** Copied from RC and modified to change the IO type of the Imp to include the Diplomatic edges * associated with each port. This drives FASED functional model sizing @@ -103,3 +104,27 @@ trait HasTraceIOImp extends LazyModuleImp { trait ExcludeInvalidBoomAssertions extends LazyModuleImp { ExcludeInstanceAsserts(("NonBlockingDCache", "dtlb")) } + +trait CanHaveBoomMultiCycleRegfileImp { + val outer: boom.system.BoomRocketSubsystem + val cores = outer.boomTiles.map(tile => tile.module.core) + cores.foreach({ core => + core.iregfile match { + case irf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(irf.regfile)) + case _ => Nil + } + + if (core.fp_pipeline != null) core.fp_pipeline.fregfile match { + case irf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(irf.regfile)) + case _ => Nil + } + + }) +} +trait CanHaveRocketMultiCycleRegfileImp { + val outer: RocketSubsystem + outer.rocketTiles.foreach({ tile => + annotate(MemModelAnnotation(tile.module.core.rocketImpl.rf.rf)) + tile.module.fpuOpt.foreach(fpu => annotate(MemModelAnnotation(fpu.fpuImpl.regfile))) + }) +} diff --git a/generators/firechip/src/main/scala/Targets.scala b/generators/firechip/src/main/scala/Targets.scala index ba966fac..33a25da2 100644 --- a/generators/firechip/src/main/scala/Targets.scala +++ b/generators/firechip/src/main/scala/Targets.scala @@ -55,6 +55,7 @@ class FireSimModuleImp[+L <: FireSim](l: L) extends RocketSubsystemModuleImp(l) with HasPeripheryIceNICModuleImpValidOnly with HasPeripheryBlockDeviceModuleImp with HasTraceIOImp + with CanHaveRocketMultiCycleRegfileImp class FireSimNoNIC(implicit p: Parameters) extends RocketSubsystem @@ -79,6 +80,7 @@ class FireSimNoNICModuleImp[+L <: FireSimNoNIC](l: L) extends RocketSubsystemMod with HasPeripheryUARTModuleImp with HasPeripheryBlockDeviceModuleImp with HasTraceIOImp + with CanHaveRocketMultiCycleRegfileImp class FireBoom(implicit p: Parameters) extends Subsystem @@ -106,6 +108,7 @@ class FireBoomModuleImp[+L <: FireBoom](l: L) extends SubsystemModuleImp(l) with HasPeripheryBlockDeviceModuleImp with HasTraceIOImp with ExcludeInvalidBoomAssertions + with CanHaveBoomMultiCycleRegfileImp class FireBoomNoNIC(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology @@ -130,6 +133,7 @@ class FireBoomNoNICModuleImp[+L <: FireBoomNoNIC](l: L) extends SubsystemModuleI with HasPeripheryBlockDeviceModuleImp with HasTraceIOImp with ExcludeInvalidBoomAssertions + with CanHaveBoomMultiCycleRegfileImp case object NumNodes extends Field[Int] diff --git a/generators/firechip/src/test/scala/ScalaTestSuite.scala b/generators/firechip/src/test/scala/ScalaTestSuite.scala index 54848ac8..44c4bff0 100644 --- a/generators/firechip/src/test/scala/ScalaTestSuite.scala +++ b/generators/firechip/src/test/scala/ScalaTestSuite.scala @@ -109,9 +109,9 @@ abstract class FireSimTestSuite( val lines = Source.fromFile(file).getLines.toList lines.filter(_.startsWith("TRACEPORT")).drop(dropLines) } - val resetLength = 50 + val resetLength = 51 val verilatedOutput = getLines(new File(outDir, s"/${verilatedLog}")) - val synthPrintOutput = getLines(new File(genDir, s"/TRACEFILE"), resetLength + 1) + val synthPrintOutput = getLines(new File(genDir, s"/TRACEFILE"), resetLength) assert(verilatedOutput.size == synthPrintOutput.size, "Outputs differ in length") assert(verilatedOutput.nonEmpty) for ( (vPrint, sPrint) <- verilatedOutput.zip(synthPrintOutput) ) { @@ -131,8 +131,9 @@ abstract class FireSimTestSuite( } class RocketF1Tests extends FireSimTestSuite("FireSimNoNIC", "FireSimRocketChipConfig", "FireSimConfig") -class RocketF1ClockDivTests extends FireSimTestSuite("FireSimNoNIC", "FireSimRocketChipConfig", "FireSimClockDivConfig") class BoomF1Tests extends FireSimTestSuite("FireBoomNoNIC", "FireSimBoomConfig", "FireSimConfig") class RocketNICF1Tests extends FireSimTestSuite("FireSim", "FireSimRocketChipConfig", "FireSimConfig") { runSuite("verilator")(NICLoopbackTests) } +class RamModelRocketF1Tests extends FireSimTestSuite("FireSimNoNIC", "FireSimRocketChipDualCoreConfig", "Midas2Config") +class RamModelBoomF1Tests extends FireSimTestSuite("FireBoomNoNIC", "FireSimBoomConfig", "Midas2Config") diff --git a/sims/firesim b/sims/firesim index 4cd75833..a3d48a43 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 4cd75833dfc1f9f796a1c5505ece6937fd253189 +Subproject commit a3d48a43a972e663e45a2ce4617a798a940d6a2b From d3cec27471576c7f4d84c13091b9b929038d18ba Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 3 Sep 2019 11:13:06 -0700 Subject: [PATCH 43/91] fix firesim makefrag --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index 4cd75833..327bc260 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 4cd75833dfc1f9f796a1c5505ece6937fd253189 +Subproject commit 327bc260022d8d159e6f77b99079dee35237d131 From 538e9edbef1884dfda2812bda0d3a760e752f4bc Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 3 Sep 2019 15:05:48 -0700 Subject: [PATCH 44/91] make big-blkdev test less big --- tests/big-blkdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/big-blkdev.c b/tests/big-blkdev.c index d065217a..94ee4415 100644 --- a/tests/big-blkdev.c +++ b/tests/big-blkdev.c @@ -5,7 +5,7 @@ #include "blkdev.h" #define SECTOR_WORDS (BLKDEV_SECTOR_SIZE / sizeof(uint64_t)) -#define TEST_SECTORS 128 +#define TEST_SECTORS 16 unsigned long sector_buf[SECTOR_WORDS]; From afe14d423dea727b9fc2d9b2c363540bb8b46938 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 2 Sep 2019 13:20:19 -0700 Subject: [PATCH 45/91] Add FireSim tests to CI --- .circleci/build-extra-tests.sh | 11 ++ .circleci/config.yml | 254 ++++++++++++++++++++++++++++++++- .circleci/defaults.sh | 5 + .circleci/do-firesim-build.sh | 60 ++++++++ .circleci/run-firesim-tests.sh | 21 +++ 5 files changed, 350 insertions(+), 1 deletion(-) create mode 100755 .circleci/build-extra-tests.sh create mode 100755 .circleci/do-firesim-build.sh create mode 100755 .circleci/run-firesim-tests.sh diff --git a/.circleci/build-extra-tests.sh b/.circleci/build-extra-tests.sh new file mode 100755 index 00000000..e38b50fe --- /dev/null +++ b/.circleci/build-extra-tests.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# turn echo on and error on earliest command +set -ex + +# get shared variables +SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )" +source $SCRIPT_DIR/defaults.sh + +make -C $LOCAL_CHIPYARD_DIR/tests clean +make -C $LOCAL_CHIPYARD_DIR/tests diff --git a/.circleci/config.yml b/.circleci/config.yml index 77a813ee..39e890d7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -88,6 +88,32 @@ jobs: key: verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} paths: - "/home/riscvuser/verilator" + build-extra-tests: + docker: + - image: riscvboom/riscvboom-images:0.0.10 + 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-v1-{{ checksum "../riscv-tools.hash" }} + - run: + name: Build extra tests + command: .circleci/build-extra-tests.sh + no_output_timeout: 120m + - save_cache: + key: extra-tests-{{ .Branch }}-{{ .Revision }} + paths: + - "/home/riscvuser/project/tests" prepare-example: docker: - image: riscvboom/riscvboom-images:0.0.10 @@ -262,6 +288,114 @@ jobs: key: hwacha-{{ .Branch }}-{{ .Revision }} paths: - "/home/riscvuser/project" + prepare-firesim: + docker: + - image: riscvboom/riscvboom-images:0.0.10 + 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-v1-{{ 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-fireboom: + docker: + - image: riscvboom/riscvboom-images:0.0.10 + 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-v1-{{ 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-firesim-clockdiv: + docker: + - image: riscvboom/riscvboom-images:0.0.10 + 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-v1-{{ 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-clockdiv + no_output_timeout: 120m + - save_cache: + key: firesim-clockdiv-{{ .Branch }}-{{ .Revision }} + paths: + - "/home/riscvuser/project" + midasexamples-run-tests: + docker: + - image: riscvboom/riscvboom-images:0.0.10 + 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-v1-{{ checksum "../riscv-tools.hash" }} + - restore_cache: + keys: + - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + - run: + name: Run midasexamples tests + command: .circleci/run-midasexamples-tests.sh example-run-tests: docker: - image: riscvboom/riscvboom-images:0.0.10 @@ -382,6 +516,89 @@ jobs: - run: name: Run hwacha tests command: .circleci/run-tests.sh hwacha + firesim-run-tests: + docker: + - image: riscvboom/riscvboom-images:0.0.10 + 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-v1-{{ 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 + fireboom-run-tests: + docker: + - image: riscvboom/riscvboom-images:0.0.10 + 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-v1-{{ 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 + firesim-clockdiv-run-tests: + docker: + - image: riscvboom/riscvboom-images:0.0.10 + 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-v1-{{ checksum "../riscv-tools.hash" }} + - restore_cache: + keys: + - firesim-clockdiv-{{ .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-clockdiv + # Order and dependencies of jobs to run workflows: @@ -400,7 +617,6 @@ workflows: build-and-test-chipyard-integration: jobs: - # Make the toolchains - install-riscv-toolchain @@ -409,6 +625,11 @@ workflows: # Build verilator - install-verilator + # Build extra tests + - build-extra-tests: + requires: + - install-riscv-toolchain + # Prepare the verilator builds - prepare-example: requires: @@ -440,6 +661,21 @@ workflows: - install-esp-toolchain - install-verilator + - prepare-firesim: + requires: + - install-riscv-toolchain + - install-verilator + + - prepare-fireboom: + requires: + - install-riscv-toolchain + - install-verilator + + - prepare-firesim-clockdiv: + requires: + - install-riscv-toolchain + - install-verilator + # Run the respective tests # Run the example tests @@ -462,3 +698,19 @@ workflows: - hwacha-run-tests: requires: - prepare-hwacha + + # Run the firesim tests + - firesim-run-tests: + requires: + - prepare-firesim + - build-extra-tests + + - fireboom-run-tests: + requires: + - prepare-fireboom + - build-extra-tests + + - firesim-clockdiv-run-tests: + requires: + - prepare-firesim-clockdiv + - build-extra-tests diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index 66cf3b3d..c254f858 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -27,6 +27,7 @@ REMOTE_ESP_DIR=$REMOTE_WORK_DIR/esp-tools-install REMOTE_CHIPYARD_DIR=$REMOTE_WORK_DIR/chipyard REMOTE_VERILATOR_DIR=$REMOTE_WORK_DIR/verilator REMOTE_SIM_DIR=$REMOTE_CHIPYARD_DIR/sims/verilator +REMOTE_FIRESIM_DIR=$REMOTE_CHIPYARD_DIR/sims/firesim/sim # local variables (aka within the docker container) LOCAL_CHECKOUT_DIR=$HOME/project @@ -35,6 +36,7 @@ LOCAL_ESP_DIR=$HOME/esp-tools-install LOCAL_CHIPYARD_DIR=$LOCAL_CHECKOUT_DIR LOCAL_VERILATOR_DIR=$HOME/verilator LOCAL_SIM_DIR=$LOCAL_CHIPYARD_DIR/sims/verilator +LOCAL_FIRESIM_DIR=$LOCAL_CHIPYARD_DIR/sims/firesim/sim # key value store to get the build strings declare -A mapping @@ -44,3 +46,6 @@ 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 GENERATOR_PACKAGE=hwacha" +mapping["firesim"]="DESIGN=FireSim TARGET_CONFIG=FireSimRocketChipConfig PLATFORM_CONFIG=FireSimConfig" +mapping["fireboom"]="DESIGN=FireBoom TARGET_CONFIG=FireSimBoomConfig PLATFORM_CONFIG=FireSimConfig" +mapping["firesim-clockdiv"]="DESIGN=FireSim TARGET_CONFIG=FireSimRocketChipConfig PLATFORM_CONFIG=FireSimClockDivConfig" diff --git a/.circleci/do-firesim-build.sh b/.circleci/do-firesim-build.sh new file mode 100755 index 00000000..c48b12a2 --- /dev/null +++ b/.circleci/do-firesim-build.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# create the different verilator builds +# argument is the make command string + +# turn echo on and error on earliest command +set -ex + +# get shared variables +SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )" +source $SCRIPT_DIR/defaults.sh + +# call clean on exit +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\"" + +clean + +# copy over riscv/esp-tools, verilator, and chipyard to remote +run "mkdir -p $REMOTE_CHIPYARD_DIR" +run "mkdir -p $REMOTE_VERILATOR_DIR" +copy $LOCAL_CHIPYARD_DIR/ $SERVER:$REMOTE_CHIPYARD_DIR +copy $LOCAL_VERILATOR_DIR/ $SERVER:$REMOTE_VERILATOR_DIR + +TOOLS_DIR=$REMOTE_RISCV_DIR +LD_LIB_DIR=$REMOTE_RISCV_DIR/lib +VERILATOR_BIN_DIR=$REMOTE_VERILATOR_DIR/install/bin + +if [ $1 = "hwacha" ]; then + TOOLS_DIR=$REMOTE_ESP_DIR + LD_LIB_DIR=$REMOTE_ESP_DIR/lib + run "mkdir -p $REMOTE_ESP_DIR" + copy $LOCAL_ESP_DIR/ $SERVER:$REMOTE_ESP_DIR +else + run "mkdir -p $REMOTE_RISCV_DIR" + copy $LOCAL_RISCV_DIR/ $SERVER:$REMOTE_RISCV_DIR +fi + +# Build MIDAS-level verilator sim +FIRESIM_VARS="${mapping[$1]}" +run "export FIRESIM_ENV_SOURCED=1; make -C $REMOTE_FIRESIM_DIR clean" +run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; \ + export PATH=\"$VERILATOR_BIN_DIR:\$PATH\"; export FIRESIM_ENV_SOURCED=1; \ + export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; \ + make -C $REMOTE_FIRESIM_DIR JAVA_ARGS=\"-Xmx8G -Xss8M\" $FIRESIM_VARS verilator" +run "rm -rf $REMOTE_CHIPYARD_DIR/project" + +# copy back the final build +mkdir -p $LOCAL_CHIPYARD_DIR +copy $SERVER:$REMOTE_CHIPYARD_DIR/ $LOCAL_CHIPYARD_DIR + +# Fix dramsim2_ini symlink +export $FIRESIM_VARS +ln -sf $LOCAL_FIRESIM_DIR/midas/src/main/resources/dramsim2_ini $LOCAL_FIRESIM_DIR/generated-src/f1/${DESIGN}-${TARGET_CONFIG}-${PLATFORM_CONFIG}/dramsim2_ini diff --git a/.circleci/run-firesim-tests.sh b/.circleci/run-firesim-tests.sh new file mode 100755 index 00000000..6add6790 --- /dev/null +++ b/.circleci/run-firesim-tests.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# turn echo on and error on earliest command +set -ex + +# get remote exec variables +SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )" +source $SCRIPT_DIR/defaults.sh + +export PATH=$LOCAL_VERILATOR_DIR/install/bin:$PATH +export FIRESIM_ENV_SOURCED=1 + +SIMULATION_ARGS="${mapping[$1]}" + +run_test_suite () { + make -C $LOCAL_FIRESIM_DIR $SIMULATION_ARGS run-${1}-tests-fast +} + +run_test_suite bmark +run_test_suite nic +run_test_suite blockdev From 9437778ceb97f5a59e41c4d9f4b4da757432bd95 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 4 Sep 2019 13:46:30 -0700 Subject: [PATCH 46/91] simplify firesim midasexamples tests --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index 327bc260..4116a8f2 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 327bc260022d8d159e6f77b99079dee35237d131 +Subproject commit 4116a8f2985906a962f2cd49ba4735479ea1ea0a From 0273cd4d9016753f40091b75d3575ad842c901c7 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 4 Sep 2019 14:01:20 -0700 Subject: [PATCH 47/91] add midasexamples to CI --- .circleci/config.yml | 6 ++++ .circleci/run-midasexamples-tests.sh | 41 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100755 .circleci/run-midasexamples-tests.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 39e890d7..88ec3e45 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -678,6 +678,12 @@ workflows: # Run the respective tests + # Run midasexamples test + - midasexamples-run-tests: + requires: + - install-riscv-toolchain + - install-verilator + # Run the example tests - example-run-tests: requires: diff --git a/.circleci/run-midasexamples-tests.sh b/.circleci/run-midasexamples-tests.sh new file mode 100755 index 00000000..592e8e2a --- /dev/null +++ b/.circleci/run-midasexamples-tests.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# turn echo on and error on earliest command +set -ex + +# get shared variables +SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )" +source $SCRIPT_DIR/defaults.sh + +# call clean on exit +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\"" + +clean + +# copy over riscv-tools, verilator, and chipyard to remote +run "mkdir -p $REMOTE_CHIPYARD_DIR" +run "mkdir -p $REMOTE_VERILATOR_DIR" +run "mkdir -p $REMOTE_RISCV_DIR" + +copy $LOCAL_CHIPYARD_DIR/ $SERVER:$REMOTE_CHIPYARD_DIR +copy $LOCAL_VERILATOR_DIR/ $SERVER:$REMOTE_VERILATOR_DIR +copy $LOCAL_RISCV_DIR/ $SERVER:$REMOTE_RISCV_DIR + +TOOLS_DIR=$REMOTE_RISCV_DIR +LD_LIB_DIR=$REMOTE_RISCV_DIR/lib +VERILATOR_BIN_DIR=$REMOTE_VERILATOR_DIR/install/bin + +# Run midasexamples test + +run "export FIRESIM_ENV_SOURCED=1; make -C $REMOTE_FIRESIM_DIR clean" +run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; \ + export PATH=\"$VERILATOR_BIN_DIR:\$PATH\"; export FIRESIM_ENV_SOURCED=1; \ + export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; \ + make -C $REMOTE_FIRESIM_DIR JAVA_ARGS=\"-Xmx8G -Xss8M\" TARGET_PROJECT=midasexamples test" From 28faff27d382f542c210d23548af9509af555474 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 4 Sep 2019 15:14:18 -0700 Subject: [PATCH 48/91] run remote builds using separate ivy2/sbt directories --- .circleci/defaults.sh | 1 + .circleci/do-firesim-build.sh | 5 ++++- .circleci/do-rtl-build.sh | 7 ++++++- .circleci/run-midasexamples-tests.sh | 7 ++++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index c254f858..8497f304 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -28,6 +28,7 @@ REMOTE_CHIPYARD_DIR=$REMOTE_WORK_DIR/chipyard REMOTE_VERILATOR_DIR=$REMOTE_WORK_DIR/verilator REMOTE_SIM_DIR=$REMOTE_CHIPYARD_DIR/sims/verilator REMOTE_FIRESIM_DIR=$REMOTE_CHIPYARD_DIR/sims/firesim/sim +REMOTE_JAVA_ARGS="-Xmx8G -Xss8M -Dsbt.ivy.home=$REMOTE_WORK_DIR/.ivy2 -Dsbt.global.base=$REMOTE_WORK_DIR/.sbt -Dsbt.boot.directory=$REMOTE_WORK_DIR/.sbt/boot" # local variables (aka within the docker container) LOCAL_CHECKOUT_DIR=$HOME/project diff --git a/.circleci/do-firesim-build.sh b/.circleci/do-firesim-build.sh index c48b12a2..ecb965b2 100755 --- a/.circleci/do-firesim-build.sh +++ b/.circleci/do-firesim-build.sh @@ -28,6 +28,9 @@ run "mkdir -p $REMOTE_VERILATOR_DIR" copy $LOCAL_CHIPYARD_DIR/ $SERVER:$REMOTE_CHIPYARD_DIR copy $LOCAL_VERILATOR_DIR/ $SERVER:$REMOTE_VERILATOR_DIR +run "cp -r ~/.ivy2 $REMOTE_WORK_DIR" +run "cp -r ~/.sbt $REMOTE_WORK_DIR" + TOOLS_DIR=$REMOTE_RISCV_DIR LD_LIB_DIR=$REMOTE_RISCV_DIR/lib VERILATOR_BIN_DIR=$REMOTE_VERILATOR_DIR/install/bin @@ -48,7 +51,7 @@ run "export FIRESIM_ENV_SOURCED=1; make -C $REMOTE_FIRESIM_DIR clean" run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; \ export PATH=\"$VERILATOR_BIN_DIR:\$PATH\"; export FIRESIM_ENV_SOURCED=1; \ export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; \ - make -C $REMOTE_FIRESIM_DIR JAVA_ARGS=\"-Xmx8G -Xss8M\" $FIRESIM_VARS verilator" + make -C $REMOTE_FIRESIM_DIR JAVA_ARGS=\"$REMOTE_JAVA_ARGS\" $FIRESIM_VARS verilator" run "rm -rf $REMOTE_CHIPYARD_DIR/project" # copy back the final build diff --git a/.circleci/do-rtl-build.sh b/.circleci/do-rtl-build.sh index c4eb04ab..50f9ce94 100755 --- a/.circleci/do-rtl-build.sh +++ b/.circleci/do-rtl-build.sh @@ -27,6 +27,9 @@ run "mkdir -p $REMOTE_VERILATOR_DIR" copy $LOCAL_CHIPYARD_DIR/ $SERVER:$REMOTE_CHIPYARD_DIR copy $LOCAL_VERILATOR_DIR/ $SERVER:$REMOTE_VERILATOR_DIR +run "cp -r ~/.ivy2 $REMOTE_WORK_DIR" +run "cp -r ~/.sbt $REMOTE_WORK_DIR" + TOOLS_DIR=$REMOTE_RISCV_DIR LD_LIB_DIR=$REMOTE_RISCV_DIR/lib if [ $1 = "hwacha" ]; then @@ -41,7 +44,9 @@ fi # enter the verilator directory and build the specific config on remote server run "make -C $REMOTE_SIM_DIR clean" -run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; make -j$NPROC -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR JAVA_ARGS=\"-Xmx8G -Xss8M\" ${mapping[$1]}" +run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; \ + export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; \ + make -j$NPROC -C $REMOTE_SIM_DIR VERILATOR_INSTALL_DIR=$REMOTE_VERILATOR_DIR JAVA_ARGS=\"$REMOTE_JAVA_ARGS\" ${mapping[$1]}" run "rm -rf $REMOTE_CHIPYARD_DIR/project" # copy back the final build diff --git a/.circleci/run-midasexamples-tests.sh b/.circleci/run-midasexamples-tests.sh index 592e8e2a..383a75ff 100755 --- a/.circleci/run-midasexamples-tests.sh +++ b/.circleci/run-midasexamples-tests.sh @@ -28,6 +28,11 @@ copy $LOCAL_CHIPYARD_DIR/ $SERVER:$REMOTE_CHIPYARD_DIR copy $LOCAL_VERILATOR_DIR/ $SERVER:$REMOTE_VERILATOR_DIR copy $LOCAL_RISCV_DIR/ $SERVER:$REMOTE_RISCV_DIR +# Copy ivy2 and sbt directories + +run "cp -r ~/.ivy2 $REMOTE_WORK_DIR" +run "cp -r ~/.sbt $REMOTE_WORK_DIR" + TOOLS_DIR=$REMOTE_RISCV_DIR LD_LIB_DIR=$REMOTE_RISCV_DIR/lib VERILATOR_BIN_DIR=$REMOTE_VERILATOR_DIR/install/bin @@ -38,4 +43,4 @@ run "export FIRESIM_ENV_SOURCED=1; make -C $REMOTE_FIRESIM_DIR clean" run "export RISCV=\"$TOOLS_DIR\"; export LD_LIBRARY_PATH=\"$LD_LIB_DIR\"; \ export PATH=\"$VERILATOR_BIN_DIR:\$PATH\"; export FIRESIM_ENV_SOURCED=1; \ export VERILATOR_ROOT=$REMOTE_VERILATOR_DIR/install/share/verilator; \ - make -C $REMOTE_FIRESIM_DIR JAVA_ARGS=\"-Xmx8G -Xss8M\" TARGET_PROJECT=midasexamples test" + make -C $REMOTE_FIRESIM_DIR JAVA_ARGS=\"$REMOTE_JAVA_ARGS\" TARGET_PROJECT=midasexamples test" From 9bf174afb37baf66804a4b67dbca14bf3ee54f0d Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Mon, 9 Sep 2019 06:41:15 +0000 Subject: [PATCH 49/91] [firechip] Update regfile optimization mixins --- .../firechip/src/main/scala/TargetMixins.scala | 13 +++++-------- generators/firechip/src/main/scala/Targets.scala | 16 ++++++++-------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/generators/firechip/src/main/scala/TargetMixins.scala b/generators/firechip/src/main/scala/TargetMixins.scala index 76dc224e..f36cf021 100644 --- a/generators/firechip/src/main/scala/TargetMixins.scala +++ b/generators/firechip/src/main/scala/TargetMixins.scala @@ -105,10 +105,10 @@ trait ExcludeInvalidBoomAssertions extends LazyModuleImp { ExcludeInstanceAsserts(("NonBlockingDCache", "dtlb")) } -trait CanHaveBoomMultiCycleRegfileImp { - val outer: boom.system.BoomRocketSubsystem - val cores = outer.boomTiles.map(tile => tile.module.core) - cores.foreach({ core => +trait CanHaveMultiCycleRegfileImp { + val outer: utilities.HasBoomAndRocketTiles + val boomCores = outer.boomTiles.map(tile => tile.module.core) + boomCores.foreach({ core => core.iregfile match { case irf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(irf.regfile)) case _ => Nil @@ -118,11 +118,8 @@ trait CanHaveBoomMultiCycleRegfileImp { case irf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(irf.regfile)) case _ => Nil } + }) - }) -} -trait CanHaveRocketMultiCycleRegfileImp { - val outer: RocketSubsystem outer.rocketTiles.foreach({ tile => annotate(MemModelAnnotation(tile.module.core.rocketImpl.rf.rf)) tile.module.fpuOpt.foreach(fpu => annotate(MemModelAnnotation(fpu.fpuImpl.regfile))) diff --git a/generators/firechip/src/main/scala/Targets.scala b/generators/firechip/src/main/scala/Targets.scala index 33a25da2..37c1f2b1 100644 --- a/generators/firechip/src/main/scala/Targets.scala +++ b/generators/firechip/src/main/scala/Targets.scala @@ -31,7 +31,7 @@ import java.io.File * determine which driver to build. *******************************************************************************/ -class FireSim(implicit p: Parameters) extends RocketSubsystem +class FireSim(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology with CanHaveFASEDOptimizedMasterAXI4MemPort with HasPeripheryBootROM @@ -45,7 +45,7 @@ class FireSim(implicit p: Parameters) extends RocketSubsystem override lazy val module = new FireSimModuleImp(this) } -class FireSimModuleImp[+L <: FireSim](l: L) extends RocketSubsystemModuleImp(l) +class FireSimModuleImp[+L <: FireSim](l: L) extends SubsystemModuleImp(l) with HasRTCModuleImp with CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp @@ -55,10 +55,10 @@ class FireSimModuleImp[+L <: FireSim](l: L) extends RocketSubsystemModuleImp(l) with HasPeripheryIceNICModuleImpValidOnly with HasPeripheryBlockDeviceModuleImp with HasTraceIOImp - with CanHaveRocketMultiCycleRegfileImp + with CanHaveMultiCycleRegfileImp -class FireSimNoNIC(implicit p: Parameters) extends RocketSubsystem +class FireSimNoNIC(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology with CanHaveFASEDOptimizedMasterAXI4MemPort with HasPeripheryBootROM @@ -71,7 +71,7 @@ class FireSimNoNIC(implicit p: Parameters) extends RocketSubsystem override lazy val module = new FireSimNoNICModuleImp(this) } -class FireSimNoNICModuleImp[+L <: FireSimNoNIC](l: L) extends RocketSubsystemModuleImp(l) +class FireSimNoNICModuleImp[+L <: FireSimNoNIC](l: L) extends SubsystemModuleImp(l) with HasRTCModuleImp with CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp @@ -80,7 +80,7 @@ class FireSimNoNICModuleImp[+L <: FireSimNoNIC](l: L) extends RocketSubsystemMod with HasPeripheryUARTModuleImp with HasPeripheryBlockDeviceModuleImp with HasTraceIOImp - with CanHaveRocketMultiCycleRegfileImp + with CanHaveMultiCycleRegfileImp class FireBoom(implicit p: Parameters) extends Subsystem @@ -108,7 +108,7 @@ class FireBoomModuleImp[+L <: FireBoom](l: L) extends SubsystemModuleImp(l) with HasPeripheryBlockDeviceModuleImp with HasTraceIOImp with ExcludeInvalidBoomAssertions - with CanHaveBoomMultiCycleRegfileImp + with CanHaveMultiCycleRegfileImp class FireBoomNoNIC(implicit p: Parameters) extends Subsystem with HasHierarchicalBusTopology @@ -133,7 +133,7 @@ class FireBoomNoNICModuleImp[+L <: FireBoomNoNIC](l: L) extends SubsystemModuleI with HasPeripheryBlockDeviceModuleImp with HasTraceIOImp with ExcludeInvalidBoomAssertions - with CanHaveBoomMultiCycleRegfileImp + with CanHaveMultiCycleRegfileImp case object NumNodes extends Field[Int] From 6b4ea0fd61c42b9110fb9a0e79e8798fa2d54565 Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Tue, 10 Sep 2019 04:26:28 +0000 Subject: [PATCH 50/91] Bump FireSim --- sims/firesim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/firesim b/sims/firesim index c4b24a41..92fe0e4d 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit c4b24a410b63dbd89c6921b1aef2252727cd29f3 +Subproject commit 92fe0e4def4d9bde0c5c36cd9090ef8c60fd0d45 From 2eeda43b934c1561a291cdf9410f3795c33f62fa Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 10 Sep 2019 14:34:52 -0700 Subject: [PATCH 51/91] make firrtl-interpreter a submodule instead of depending on external snapshot --- .gitmodules | 3 +++ build.sbt | 15 ++++++++++++--- project/plugins.sbt | 1 + tools/firrtl-interpreter | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) create mode 160000 tools/firrtl-interpreter diff --git a/.gitmodules b/.gitmodules index cad55a67..4bbfaa97 100644 --- a/.gitmodules +++ b/.gitmodules @@ -58,3 +58,6 @@ [submodule "generators/rocc-template"] path = generators/sha3 url = https://github.com/ucb-bar/rocc-template.git +[submodule "tools/firrtl-interpreter"] + path = tools/firrtl-interpreter + url = https://github.com/freechipsproject/firrtl-interpreter.git diff --git a/build.sbt b/build.sbt index 1dbaf219..417b910e 100644 --- a/build.sbt +++ b/build.sbt @@ -13,8 +13,8 @@ lazy val commonSettings = Seq( libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % "test", libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.1", libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value, - libraryDependencies += "edu.berkeley.cs" %% "firrtl-interpreter" % "1.2-SNAPSHOT", libraryDependencies += "com.github.scopt" %% "scopt" % "3.7.0", + libraryDependencies += "org.scala-lang.modules" % "scala-jline" % "2.12.1", addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full), resolvers ++= Seq( Resolver.sonatypeRepo("snapshots"), @@ -67,15 +67,23 @@ def isolateAllTests(tests: Seq[TestDefinition]) = tests map { test => } toSeq // Subproject definitions begin +// +lazy val firrtl = (project in file("tools/firrtl")) + .settings(commonSettings) + +lazy val firrtl_interpreter = (project in file("tools/firrtl-interpreter")) + .dependsOn(firrtl) + .settings(commonSettings) // NB: FIRRTL dependency is unmanaged (and dropped in sim/lib) lazy val chisel = (project in rocketChipDir / "chisel3") lazy val treadle = freshProject("treadle", file("tools/treadle")) + .dependsOn(firrtl) .settings(commonSettings) lazy val `chisel-testers` = freshProject("chisel-testers", file("./tools/chisel-testers")) - .dependsOn(treadle, chisel) + .dependsOn(treadle, firrtl_interpreter, chisel) .settings( commonSettings, libraryDependencies ++= Seq( @@ -134,6 +142,7 @@ lazy val sha3 = (project in file("generators/sha3")) .settings(commonSettings) lazy val tapeout = conditionalDependsOn(project in file("./tools/barstools/tapeout/")) + .dependsOn(firrtl_interpreter) .settings(commonSettings) lazy val mdf = (project in file("./tools/barstools/mdf/scalalib/")) @@ -145,7 +154,7 @@ lazy val barstoolsMacros = (project in file("./tools/barstools/macros/")) .settings(commonSettings) lazy val dsptools = freshProject("dsptools", file("./tools/dsptools")) - .dependsOn(chisel, `chisel-testers`) + .dependsOn(chisel, `chisel-testers`, firrtl_interpreter) .settings( commonSettings, libraryDependencies ++= Seq( diff --git a/project/plugins.sbt b/project/plugins.sbt index 9d35b376..3321d801 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -13,5 +13,6 @@ addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6") addSbtPlugin("com.simplytyped" % "sbt-antlr4" % "0.8.1") addSbtPlugin("com.github.gseitz" % "sbt-protobuf" % "0.6.3") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.4") libraryDependencies += "com.github.os72" % "protoc-jar" % "3.5.1.1" diff --git a/tools/firrtl-interpreter b/tools/firrtl-interpreter new file mode 160000 index 00000000..a881c07d --- /dev/null +++ b/tools/firrtl-interpreter @@ -0,0 +1 @@ +Subproject commit a881c07df6bceea462dbbd9a28e25721a1e88567 From 622e6def6aff03e8743883afe21e4f571cd762e3 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 10 Sep 2019 16:13:17 -0700 Subject: [PATCH 52/91] chisel-testers is dependency of tapeout --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 417b910e..2468a352 100644 --- a/build.sbt +++ b/build.sbt @@ -142,7 +142,7 @@ lazy val sha3 = (project in file("generators/sha3")) .settings(commonSettings) lazy val tapeout = conditionalDependsOn(project in file("./tools/barstools/tapeout/")) - .dependsOn(firrtl_interpreter) + .dependsOn(firrtl_interpreter, `chisel-testers`) .settings(commonSettings) lazy val mdf = (project in file("./tools/barstools/mdf/scalalib/")) From 34612e559cfd1892c0da487b66b74c7bc529f423 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 10 Sep 2019 18:13:22 -0700 Subject: [PATCH 53/91] clean up dependencies --- build.sbt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index 2468a352..1ab82f27 100644 --- a/build.sbt +++ b/build.sbt @@ -68,6 +68,10 @@ def isolateAllTests(tests: Seq[TestDefinition]) = tests map { test => // Subproject definitions begin // +// NB: FIRRTL should not be a managed dependency of chisel or rocketchip. +// Instead, they will get firrtl from the JAR file placed in /lib +lazy val chisel = (project in rocketChipDir / "chisel3") + lazy val firrtl = (project in file("tools/firrtl")) .settings(commonSettings) @@ -75,9 +79,6 @@ lazy val firrtl_interpreter = (project in file("tools/firrtl-interpreter")) .dependsOn(firrtl) .settings(commonSettings) -// NB: FIRRTL dependency is unmanaged (and dropped in sim/lib) -lazy val chisel = (project in rocketChipDir / "chisel3") - lazy val treadle = freshProject("treadle", file("tools/treadle")) .dependsOn(firrtl) .settings(commonSettings) @@ -142,19 +143,19 @@ lazy val sha3 = (project in file("generators/sha3")) .settings(commonSettings) lazy val tapeout = conditionalDependsOn(project in file("./tools/barstools/tapeout/")) - .dependsOn(firrtl_interpreter, `chisel-testers`) + .dependsOn(`chisel-testers`) .settings(commonSettings) lazy val mdf = (project in file("./tools/barstools/mdf/scalalib/")) .settings(commonSettings) lazy val barstoolsMacros = (project in file("./tools/barstools/macros/")) - .dependsOn(mdf, rocketchip) + .dependsOn(firrtl_interpreter, mdf, rocketchip) .enablePlugins(sbtassembly.AssemblyPlugin) .settings(commonSettings) lazy val dsptools = freshProject("dsptools", file("./tools/dsptools")) - .dependsOn(chisel, `chisel-testers`, firrtl_interpreter) + .dependsOn(chisel, `chisel-testers`) .settings( commonSettings, libraryDependencies ++= Seq( From b748dcf14ee5041ef9e92192894f2abe74dd1658 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 5 Sep 2019 18:05:15 -0700 Subject: [PATCH 54/91] update 'Adding an Accelerator' for API changes --- docs/Customization/Adding-An-Accelerator.rst | 51 +++++++++++--------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/docs/Customization/Adding-An-Accelerator.rst b/docs/Customization/Adding-An-Accelerator.rst index 90a74733..65cbc9b2 100644 --- a/docs/Customization/Adding-An-Accelerator.rst +++ b/docs/Customization/Adding-An-Accelerator.rst @@ -123,16 +123,15 @@ For a simple memory-mapped peripheral, this just involves connecting the periphe .. code-block:: scala - trait HasPeripheryPWM extends HasSystemNetworks { + trait HasPeripheryPWM { this: BaseSubsystem => implicit val p: Parameters private val address = 0x2000 + private val portName = "pwm" - val pwm = LazyModule(new PWMTL( - PWMParams(address, peripheryBusConfig.beatBytes))(p)) + val pwm = LazyModule(new PWMTL(PWMParams(address, pbus.beatBytes))) - pwm.node := TLFragmenter( - peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node) + pbus.toVariableWidthSlave(Some(portName)) { pwm.node } } @@ -146,7 +145,7 @@ We then connect the ``PWMTL``'s pwmout to the pwmout we declared. .. code-block:: scala - trait HasPeripheryPWMModuleImp extends LazyMultiIOModuleImp { + trait HasPeripheryPWMModuleImp extends LazyModuleImp { implicit val p: Parameters val outer: HasPeripheryPWM @@ -160,33 +159,39 @@ This code is from ``generators/example/src/main/scala/Top.scala``. .. code-block:: scala - class ExampleTopWithPWM(q: Parameters) extends ExampleTop(q) - with PeripheryPWM { - override lazy val module = Module( - new ExampleTopWithPWMModule(p, this)) + class TopWithPWM(implicit p: Parameters) extends Top(p) + with HasPeripheryPWM { + override lazy val module = Module(new TopWithPWMModule(this)) } - class ExampleTopWithPWMModule(l: ExampleTopWithPWM) - extends ExampleTopModule(l) with HasPeripheryPWMModuleImp + class TopWithPWMModule(l: TopWithPWM) extends TopModule(l) + with HasPeripheryPWMModuleImp Just as we need separate traits for ``LazyModule`` and module implementation, we need two classes to build the system. -The ``ExampleTop`` classes already have the basic peripherals included for us, so we will just extend those. +The ``Top`` classes already have the basic peripherals included for us, so we will just extend those. -The ``ExampleTop`` class includes the pre-elaboration code and also a ``lazy val`` to produce the module implementation (hence ``LazyModule``). -The ``ExampleTopModule`` class is the actual RTL that gets synthesized. +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. -Finally, we need to add a configuration class in ``generators/example/src/main/scala/Configs.scala`` that tells the ``TestHarness`` to instantiate ``ExampleTopWithPWM`` instead of the default ``ExampleTop``. +Next, we need to add a configuration mixin in ``generators/example/src/main/scala/ConfigMixins.scala`` that tells the ``TestHarness`` to instantiate ``TopWithPWM`` instead of the default ``Top``. .. code-block:: scala - class WithPWM extends Config((site, here, up) => { + class WithPWMTop extends Config((site, here, up) => { case BuildTop => (p: Parameters) => - Module(LazyModule(new ExampleTopWithPWM()(p)).module) + Module(LazyModule(new TopWithPWM()(p)).module) }) - class PWMConfig extends Config(new WithPWM ++ new BaseExampleConfig) +And finally, we create a configuration class in ``generators/example/src/main/scala/RocketConfigs.scala`` that uses this mixin. +.. code-block:: scala + + class PWMRocketConfig extends Config( + new WithPWMTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) Now we can test that the PWM is working. The test program is in ``tests/pwm.c``. @@ -293,7 +298,9 @@ For instance, if we wanted to add the previously defined accelerator and route c }) class CustomAcceleratorConfig extends Config( - new WithCustomAccelerator ++ new DefaultExampleConfig) + 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 ------------------- @@ -324,7 +331,7 @@ To add a device like that, you would do the following. val dma = LazyModule(new DMADevice) - fsb.node := dma.node + fbus.fromPort(Some(portName))() := dma.node } trait HasPeripheryDMAModuleImp extends LazyMultiIOModuleImp { @@ -334,6 +341,6 @@ To add a device like that, you would do the following. The ``ExtBundle`` contains the signals we connect off-chip that we get data from. -The DMADevice also has a Tilelink client port that we connect into the L1-L2 crossbar through the front-side buffer (fsb). +The DMADevice also has a Tilelink client port that we connect into the L1-L2 crossbar through the frontend bus (fbus). The sourceId variable given in the ``TLClientNode`` instantiation determines the range of ids that can be used in acquire messages from this device. Since we specified [0, 1) as our range, only the ID 0 can be used. From ea1d3d62ea336c8964a5143a1ada2af97b6810ce Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 5 Sep 2019 18:43:06 -0700 Subject: [PATCH 55/91] add section about RocketChip generator --- docs/Generators/RocketChip.rst | 66 +++++++++++++++++++++++++++++ docs/Generators/index.rst | 2 +- docs/images/rocketchip-diagram.png | Bin 0 -> 109009 bytes 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 docs/Generators/RocketChip.rst create mode 100644 docs/images/rocketchip-diagram.png diff --git a/docs/Generators/RocketChip.rst b/docs/Generators/RocketChip.rst new file mode 100644 index 00000000..60b1e1cd --- /dev/null +++ b/docs/Generators/RocketChip.rst @@ -0,0 +1,66 @@ +RocketChip +========== + +RocketChip is an SoC generator supported by SiFive. Chipyard uses RocketChip +as the basis for producing a RISC-V SoC including Rocket, BOOM, and/or Hwacha. + +A detailed diagram of a typical RocketChip system is shown below. + +.. image:: ../images/rocketchip-diagram.png + +Tiles +----- + +This is a dual-core ``Rocket`` system. Each ``Rocket`` core is grouped with a +page-table walker, L1 instruction cache, and L1 data cache into a ``RocketTile``. + +The ``Rocket`` core can also be swapped for a ``BOOM`` core. Each tile can +also be configured with a RoCC accelerator that connects to the core as a +coprocessor. + +Memory System +------------- +The tiles connect to the ``SystemBus``, which connect it to the L2 cache banks. +The L2 cache banks then connect to the ``MemoryBus``, which connects to the +DRAM controller through a TileLink to AXI converter. + +To learn more about the memory hierarchy, see :ref:`Memory Hierarchy`. + +MMIO +---- + +For MMIO peripherals, the ``SystemBus`` connects to the ``ControlBus`` and ``PeripheryBus``. + +The ``ControlBus`` attaches standard peripherals like the BootROM, the +Platform-Level Interrupt Controller (PLIC), the core-local interrupts (CLINT), +and the Debug Unit. + +The BootROM contains the first stage bootloader, the first instructions to run +when the system comes out of reset. It also contains the Device Tree, which is +used by Linux to determine what other peripherals are attached. + +The PLIC aggregates and masks device interrupts and external interrupts. + +The core-local interrupts include software interrupts and timer interrupts for +each CPU. + +The Debug Unit is used to control the chip externally. It can be used to load +data and instructions to memory or pull data from memory. It can be controlled +through a custom DMI or standard JTAG protocol. + +The ``PeripheryBus`` attaches additional peripherals like the NIC and Block Device. +It can also optionally expose an external AXI4 port, which can be attached to +vendor-supplied AXI4 IP. + +To learn more about adding MMIO peripherals, check out the :ref:`MMIO Peripheral` +section of :ref:`Adding An Accelerator/Device`. + +DMA +--- + +You can also add DMA devices that read and write directly from the memory +system. These are attached to the ``FrontendBus``. The ``FrontendBus`` can also +connect vendor-supplied AXI4 DMA devices through an AXI4 to TileLink converter. + +To learn more about adding DMA devices, see the :ref:`Adding a DMA port` section +of :ref:`Adding an Accelerator/Device`. diff --git a/docs/Generators/index.rst b/docs/Generators/index.rst index a01b5adc..a147ffeb 100644 --- a/docs/Generators/index.rst +++ b/docs/Generators/index.rst @@ -14,4 +14,4 @@ The following pages introduce the generators integrated with the Chipyard framew Rocket BOOM Hwacha - + RocketChip diff --git a/docs/images/rocketchip-diagram.png b/docs/images/rocketchip-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..febc2e870a834363e8ff7becfe9cda51d31c9e37 GIT binary patch literal 109009 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%0DYR-KJ+JVxUmjj6y^LSnr$k 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 Zq)qPrG^Nfqoe=PW%B#zjJ~n&(KLF8_yJ!Fa literal 0 HcmV?d00001 From d411dd9a6c6fb3aacf28bebccd1f1786babb2289 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 5 Sep 2019 19:20:50 -0700 Subject: [PATCH 56/91] fill out Memory Hierarchy section --- docs/Customization/Memory-Hierarchy.rst | 104 +++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/docs/Customization/Memory-Hierarchy.rst b/docs/Customization/Memory-Hierarchy.rst index fc9792c4..2b9ff06b 100644 --- a/docs/Customization/Memory-Hierarchy.rst +++ b/docs/Customization/Memory-Hierarchy.rst @@ -1,4 +1,104 @@ Memory Hierarchy =============================== -TODO: Talk about SiFive Cache, and integration with L1 and backing main memory models -(maybe even Tilelink) + +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 +configure 4 KiB direct-mapped caches for L1I and L1D. + +.. code-block:: scala + + import freechips.rocketchip.subsystem.{WithNMediumCores, WithNSmallCores} + + class SmallRocketConfig extends Config( + new WithNSmallCores(1) ++ + new RocketConfig) + + class MediumRocketConfig extends Config( + new WithNMediumCores(1) ++ + new RocketConfig) + +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. + +.. code-block:: scala + + import freechips.rocketchip.subsystem.{WithNoMemPort, WithScratchpadsOnly} + + class ScratchpadRocketConfig extends Config( + new WithNoMemPort ++ + new WithScratchpadsOnly ++ + new SmallRocketConfig) + +The SiFive L2 Cache +------------------- + +The default RocketConfig provided in the Chipyard example project uses SiFive's +InclusiveCache generator to produce a shared L2 cache. In the default +configuration, the L2 uses a single cache bank with 512 KiB capacity and 8-way +set-associativity. However, you can change these parameters to obtain your +desired cache configuration. The main restriction is that the number of ways +and the number of banks must be powers of 2. + +.. code-block:: scala + + import freechips.rocketchip.subsystem.WithInclusiveCache + + # Create an SoC with 1 MB, 4-way, 4-bank cache + class MyCacheRocketConfig extends Config( + new WithInclusiveCache( + capacityKB = 1024, + nWays = 4, + nBanks = 4) ++ + new RocketConfig) + +The Broadcast Hub +---------------- + +If you do not want to use the L2 cache (say, for a resource-limited embedded +design), you can create a configuration without it. Instead of using the L2 +cache, you will instead use RocketChip's TileLink broadcast hub. + +.. code-block:: scala + + import freechips.rocketchip.subsystem.{WithNBigCores, BaseConfig} + + class CachelessRocketConfig extends Config( + new WithTop ++ + new WithBootROM ++ + new WithNBigCores(1) ++ + new BaseConfig) + +If you want to reduce the resources used even further, you can configure +the Broadcast Hub to use a bufferless design. + +.. code-block:: scala + + import freechips.rocketchip.subsystem.WithBufferlessBroadcastHub + + class BufferlessRocketConfig extends Config( + new WithBufferlessBroadcastHub ++ + new CachelessRocketConfig) + +The Outer Memory System +----------------------- + +The L2 coherence agent (either L2 cache of Broadcast Hub) makes requests to +an outer memory system consisting of an AXI4-compatible DRAM controller. + +The default configuration uses a single memory channel, but you can configure +the system to use multiple channels. As with the number of L2 banks, the +number of DRAM channels is restricted to powers of two. + +.. code-block:: scala + + import freechips.rocketchip.subsystem.WithNMemoryChannels + + class DualChannelRocketConfig extends Config( + new WithNMemoryChannels(2) ++ + new RocketConfig) From 803a5511dae5b33c4c05b57479e0b9ce706db5a6 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Fri, 6 Sep 2019 12:46:18 -0700 Subject: [PATCH 57/91] get rid of unused captions in ToC tree --- docs/index.rst | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 1f41b4ed..b9174005 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,39 +14,20 @@ New to Chipyard? Jump to the :ref:`Chipyard Basics` page for more info. .. toctree:: :maxdepth: 3 - :caption: Contents: :numbered: Chipyard-Basics/index - :maxdepth: 3 - :caption: Simulation: - :numbered: Simulation/index - :maxdepth: 3 - :caption: Generators: - :numbered: Generators/index - :maxdepth: 3 - :caption: Tools: - :numbered: Tools/index - :maxdepth: 3 - :caption: VLSI Production: - :numbered: VLSI/index - :maxdepth: 3 - :caption: Customization: - :numbered: Customization/index - :maxdepth: 3 - :caption: Advanced Usage: - :numbered: Advanced-Usage/index From b52b1d1c3ef02b4d0d87307187986761f1c0ee8b Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Fri, 6 Sep 2019 12:49:55 -0700 Subject: [PATCH 58/91] don't tell users to use deprecated setResource --- docs/Advanced-Usage/Resources.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/Advanced-Usage/Resources.rst b/docs/Advanced-Usage/Resources.rst index 538c43b0..788e43be 100644 --- a/docs/Advanced-Usage/Resources.rst +++ b/docs/Advanced-Usage/Resources.rst @@ -1,8 +1,8 @@ Accessing Scala Resources =============================== -A simple way to copy over a source file to the build directory to be used for a simulation compile or VLSI flow is to use the ``setResource`` or ``addResource`` functions given by FIRRTL. -They can be used in the following way: +A simple way to copy over a source file to the build directory to be used for a simulation compile or VLSI flow is to use the ``addResource`` functions given by FIRRTL. +It can be used in the following way: .. code-block:: scala @@ -14,13 +14,13 @@ They can be used in the following way: val exit = Output(Bool()) }) - setResource("/testchipip/vsrc/SimSerial.v") - setResource("/testchipip/csrc/SimSerial.cc") + addResource("/testchipip/vsrc/SimSerial.v") + addResource("/testchipip/csrc/SimSerial.cc") } In this example, the ``SimSerial`` files will be copied from a specific folder (in this case the ``path/to/testchipip/src/main/resources/testchipip/...``) to the build folder. -The ``set/addResource`` path retrieves resources from the ``src/main/resources`` directory. -So to get an item at ``src/main/resources/fileA.v`` you can use ``setResource("/fileA.v")``. +The ``addResource`` path retrieves resources from the ``src/main/resources`` directory. +So to get an item at ``src/main/resources/fileA.v`` you can use ``addResource("/fileA.v")``. However, one caveat of this approach is that to retrieve the file during the FIRRTL compile, you must have that project in the FIRRTL compiler's classpath. Thus, you need to add the SBT project as a dependency to the FIRRTL compiler in the Chipyard ``build.sbt``, which in Chipyards case is the ``tapeout`` project. For example, you added a new project called ``myAwesomeAccel`` in the Chipyard ``build.sbt``. From c0f49a47d8000f1efc498eed1942df5d83e0e32b Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Fri, 6 Sep 2019 14:09:47 -0700 Subject: [PATCH 59/91] more fixes to Adding an Accelerator --- docs/Customization/Adding-An-Accelerator.rst | 23 ++++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/Customization/Adding-An-Accelerator.rst b/docs/Customization/Adding-An-Accelerator.rst index 65cbc9b2..336c9349 100644 --- a/docs/Customization/Adding-An-Accelerator.rst +++ b/docs/Customization/Adding-An-Accelerator.rst @@ -75,7 +75,7 @@ To create a RegisterRouter-based peripheral, you will need to specify a paramete val pwmout = Output(Bool()) } - trait PWMTLModule { + trait PWMTLModule extends HasRegMap { val io: PWMTLBundle implicit val p: Parameters def params: PWMParams @@ -159,7 +159,7 @@ This code is from ``generators/example/src/main/scala/Top.scala``. .. code-block:: scala - class TopWithPWM(implicit p: Parameters) extends Top(p) + class TopWithPWM(implicit p: Parameters) extends Top with HasPeripheryPWM { override lazy val module = Module(new TopWithPWMModule(this)) } @@ -311,22 +311,23 @@ To add a device like that, you would do the following. .. code-block:: scala class DMADevice(implicit p: Parameters) extends LazyModule { - val node = TLClientNode(TLClientParameters( - name = "dma-device", sourceId = IdRange(0, 1))) + val node = TLHelper.makeClientNode( + name = "dma-device", sourceId = IdRange(0, 1)) lazy val module = new DMADeviceModule(this) } class DMADeviceModule(outer: DMADevice) extends LazyModuleImp(outer) { val io = IO(new Bundle { - val mem = outer.node.bundleOut val ext = new ExtBundle }) + val (mem, edge) = outer.node.out(0) + // ... rest of the code ... } - trait HasPeripheryDMA extends HasSystemNetworks { + trait HasPeripheryDMA { this: BaseSubsystem => implicit val p: Parameters val dma = LazyModule(new DMADevice) @@ -334,11 +335,19 @@ To add a device like that, you would do the following. fbus.fromPort(Some(portName))() := dma.node } - trait HasPeripheryDMAModuleImp extends LazyMultiIOModuleImp { + trait HasPeripheryDMAModuleImp extends LazyModuleImp { val ext = IO(new ExtBundle) ext <> outer.dma.module.io.ext } + class TopWithDMA(implicit p: Parameters) extends Top + with HasPeripheryDMA { + override lazy val module = new TopWithDMAModule + } + + class TopWithDMAModule(l: TopWithDMA) extends TopModule(l) + with HasPeripheryDMAModuleImp + The ``ExtBundle`` contains the signals we connect off-chip that we get data from. The DMADevice also has a Tilelink client port that we connect into the L1-L2 crossbar through the frontend bus (fbus). From dfbf87061b8f91b44d6bf9496f4971f19ccc73f4 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Fri, 6 Sep 2019 23:34:43 -0700 Subject: [PATCH 60/91] get started on documenting TileLink/Diplomacy --- .../Diplomacy-Connectors.rst | 38 +++ .../EdgeFunctions.rst | 158 +++++++++ .../NodeTypes.rst | 311 ++++++++++++++++++ .../Register-Router.rst | 2 + docs/TileLink-Diplomacy-Reference/Widgets.rst | 2 + docs/TileLink-Diplomacy-Reference/index.rst | 29 ++ docs/index.rst | 1 + 7 files changed, 541 insertions(+) create mode 100644 docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst create mode 100644 docs/TileLink-Diplomacy-Reference/EdgeFunctions.rst create mode 100644 docs/TileLink-Diplomacy-Reference/NodeTypes.rst create mode 100644 docs/TileLink-Diplomacy-Reference/Register-Router.rst create mode 100644 docs/TileLink-Diplomacy-Reference/Widgets.rst create mode 100644 docs/TileLink-Diplomacy-Reference/index.rst diff --git a/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst b/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst new file mode 100644 index 00000000..2ff210de --- /dev/null +++ b/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst @@ -0,0 +1,38 @@ +Diplomacy Connectors +==================== + +Nodes in a diplomacy graph are connected to each other with edges. The diplomacy +library provides four operators that can be used to form edges between nodes. + +:= +-- + +This is the basic connection operator. It is the same syntax as the Chisel +uni-directional connector, but it is not equivalent. This operator connects +diplomacy node, not Chisel bundles. + +The basic connection operator always creates a single edge between the two +nodes. + +:=* +--- + +This is a "query" type connection operator. It can create multiple edges +between nodes, with the number of edges determined by the client node +(the node on the right side of the operator). This can be useful if you +are connecting a multi-edge client to a nexus node or adapter node. + +:*= +--- + +This is a "star" type connection operator. It also creates multiple edges, +but the number of edges is determined by the manager (left side of operator), +rather than the client. It's useful for connecting nexus nodes to multi-edge +manager nodes. + +:*=* +---- + +This is a "flex" connection operator. It creates multiple edges based on +whichever side of the operator has a known number of edges. This can be used +in generators where the type of node on either side isn't known until runtime. diff --git a/docs/TileLink-Diplomacy-Reference/EdgeFunctions.rst b/docs/TileLink-Diplomacy-Reference/EdgeFunctions.rst new file mode 100644 index 00000000..984525ce --- /dev/null +++ b/docs/TileLink-Diplomacy-Reference/EdgeFunctions.rst @@ -0,0 +1,158 @@ +TileLink Edge Object Methods +============================ + +The edge object associated with a TileLink node has several helpful methods +for constructing TileLink messages and retrieving data from them. + + +Get +--- + +Constructor for a TLBundleA encoding a ``Get`` message, which requests data +from memory. The D channel response to this message will be an +``AccessAckData``, which may have multiple beats. + +**Arguments:** + + - ``fromSource: UInt`` - Source ID for this transaction + - ``toAddress: UInt`` - The address to read from + - ``lgSize: UInt`` - Base two logarithm of the number of bytes to be read + +Put +--- + +Constructor for a TLBundleA encoding a ``PutFull`` or ``PutPartial`` message, +which write data to memory. It will be a ``PutPartial`` if the ``mask`` is +specified and a ``PutFull`` if it is omitted. The put may require multiple +beats. If that is the case, only ``data`` and ``mask`` should change for each +beat. All other fields must be the same for all beats in the transaction, +including the address. The manager will respond to this message with a single +``AccessAck``. + +**Arguments:** + + - ``fromSource: UInt`` - Source ID for this transaction. + - ``toAddress: UInt`` - The address to write to. + - ``lgSize: UInt`` - Base two logarithm of the number of bytes to be written. + - ``data: UInt`` - The data to write on this beat. + - ``mask: UInt`` - (optional) The write mask for this beat. + +Arithmetic +---------- + +Constructor for a TLBundleA encoding an ``Arithmetic`` message, which is an +atomic operation. The possible values for the ``atomic`` field are defined +in the ``TLAtomics`` object. It can be ``MIN``, ``MAX``, ``MINU``, ``MAXU``, or +``ADD``, which correspond to atomic minimum, maximum, unsigned minimum, unsigned +maximum, or addition operations, respectively. The previous value at the +memory location will be returned in the response, which will be in the form +of an ``AccessAckData``. + +**Arguments:** + + - ``fromSource: UInt`` - Source ID for this transaction. + - ``toAddress: UInt`` - The address to perform an arithmetic operation on. + - ``lgSize: UInt`` - Base two logarithm of the number of bytes to operate on. + - ``data: UInt`` - Right-hand operand of the arithmetic operation + - ``atomic: UInt`` - Arithmetic operation type (from ``TLAtomics``) + +Logical +------- + +Constructor for a TLBundleA encoding a ``Logical`` message, an atomic operation. +The possible values for the ``atomic`` field are ``XOR``, ``OR``, ``AND``, and +``SWAP``, which correspond to atomic bitwise exclusive or, bitwise inclusive or, +bitwise and, and swap operations, respectively. The previous value at the +memory location will be returned in an ``AccessAckData`` response. + +**Arguments:** + + - ``fromSource: UInt`` - Source ID for this transaction. + - ``toAddress: UInt`` - The address to perform a logical operation on. + - ``lgSize: UInt`` - Base two logarithm of the number of bytes to operate on. + - ``data: UInt`` - Right-hand operand of the logical operation + - ``atomic: UInt`` - Logical operation type (from ``TLAtomics``) + +Hint +---- + +Constructor for a TLBundleA encoding a ``Hint`` message, which is used to +send prefetch hints to caches. The ``param`` argument determines what kind +of hint it is. The possible values come from the ``TLHints`` object and are +``PREFETCH_READ`` and ``PREFETCH_WRITE``. The first one tells caches to +acquire data in a shared state. The second one tells cache to acquire data +in an exclusive state. If the cache this message reaches is a last-level cache, +there won't be any difference. If the manager this message reaches is not a +cache, it will simply be ignored. In any case, a ``HintAck`` message will be +sent in response. + +**Arguments:** + + - ``fromSource: UInt`` - Source ID for this transaction. + - ``toAddress: UInt`` - The address to prefetch + - ``lgSize: UInt`` - Base two logarithm of the number of bytes to prefetch + - ``param: UInt`` - Hint type (from TLHints) + +AccessAck +--------- + +Constructor for a TLBundleD encoding an ``AccessAck`` or ``AccessAckData`` +message. If the optional ``data`` field is supplied, it will be an +``AccessAckData``. Otherwise, it will be an ``AccessAck``. + +**Arguments** + + - ``a: TLBundleA`` - The A channel message to acknowledge + - ``data: UInt`` - (optional) The data to send back + +HintAck +------- + +Constructor for a TLBundleD encoding a ``HintAck`` message. + +**Arguments** + + - ``a: TLBundleA`` - The A channel message to acknowledge + +first/last/count +---------------- + +These methods take a decoupled channel (either the A channel or D channel) +and determines whether the current beat is the first of the transaction, +whether the current beat is the last in the transaction, or the count +(starting from 0) of the current beat in the transaction. + +**Arguments:** + + - ``x: DecoupledIO[TLChannel]`` - The decoupled channel to snoop on. + +numBeats +--------- + +This method takes in a TileLink bundle and gives the number of beats expected +for the transaction. + +**Arguments:** + + - ``x: TLChannel`` - The TileLink bundle to get the number of beats from + +numBeats1 +--------- + +Similar to ``numBeats`` except it gives the number of beats minus one. If this +is what you need, you should use this instead of doing ``numBeats - 1.U``, as +this is more efficient. + +**Arguments:** + + - ``x: TLChannel`` - The TileLink bundle to get the number of beats from + +hasData +-------- + +Determines whether the TileLink message contains data or not. This is true +if the message is a PutFull, PutPartial, Arithmetic, Logical, or AccessAckData. + +**Arguments:** + + - ``x: TLChannel`` - The TileLink bundle to check diff --git a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst new file mode 100644 index 00000000..ace3d310 --- /dev/null +++ b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst @@ -0,0 +1,311 @@ +TileLink Node Types +=================== + +Diplomacy represents the different components of an SoC as nodes of a +directed acyclic graph. TileLink nodes can come in several different types. + +Client Node +----------- + +TileLink clients are modules that initiate TileLink transactions by sending +requests on the A channel and receive responses on the D channel. If the +client implements TL-C, it will receive probes on the B channel, send releases +on the C channel, and send grant acknowledgements on the E channel. + +The L1 caches and DMA devices in RocketChip/Chipyard have client nodes. + +You can add a TileLink client node to your LazyModule using the TLHelper +object from testchipip like so: + +.. code-block:: scala + + import freechips.rocketchip.config.Parameters + import freechips.rocketchip.diplomacy._ + import freechips.rocketchip.tilelink.{TLClientParameters} + import testchipip.TLHelper + + class MyClient(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeClientNode(TLClientParameters( + name = "my-client", + sourceId = IdRange(0, 4), + requestFifo = true, + visibility = Seq(AddressSet(0, 0xffff)))) + + lazy val module = new LazyModuleImp(this) { + val (tl, edge) = node.out(0) + + // Rest of code here + } + } + +The ``name`` argument identifies the node in the diplomacy graph. It is the +only required argument for TLClientParameters. + +The ``sourceId`` argument specifies the range of source identifiers that this +client will use. Since we have set the range to [0, 4) here, this client will +be able to send up to four requests in flight at a time. Each request will +have a distinct value in its source field. The default value for this field +is ``IdRange(0, 1)``, which means it would only be able to send a single +request inflight. + +The ``requestFifo`` argument is a boolean option which defaults to false. +If it is set to true, the client will request that downstream managers that +support it send responses in FIFO order (that is, in the same order the +corresponding requests were sent). + +The ``visibility`` argument specifies the address ranges that the client +will access. By default it is set to include all addresses. In this example, +we set it to contain a single address range ``AddressSet(0, 0xffff)``, which +means that the client will only access addresses in this range. Clients +normally do not specify this, but it can help downstream crossbar generators +optimize the hardware by not arbitrating the client to managers with address +ranges that don't overlap with its visibility. + +Inside your lazy module implementation, you can call ``node.out`` to get a +list of bundle/edge pairs. If you used the TLHelper, you only specified a +single client edge, so this list will only have one pair. + +The ``tl`` bundle is a Chisel hardware bundle that connects to the IO of this +module. It contains two (in the case of TL-UL and TL-UH) or five (in the case +of TL-C) decoupled bundles corresponding to the TileLink channels. This is +what you should connect your hardware logic to in order to actually send/receive +TileLink messages. + +The ``edge`` object represents the edge of the diplomacy graph. It contains +some useful helper functions which will be documented in +:ref:`TileLink Edge Object Methods`. + +Manager Node +------------ + +TileLink managers take requests from clients on the A channel and send +responses back on the D channel. You can create a manager node using the +TLHelper like so: + +.. code-block:: scala + + import freechips.rocketchip.config.Parameters + import freechips.rocketchip.diplomacy._ + import freechips.rocketchip.tilelink.{TLManagerParameters} + import testchipip.TLHelper + + class MyManager(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice("my-device", Seq("tutorial,my-device0")) + val beatBytes = 8 + val node = TLHelper.makeManagerNode(beatBytes, TLManagerParameters( + address = Seq(AddressSet(0x20000, 0xfff)), + resources = device.reg, + regionType = RegionType.UNCACHED, + executable = true, + supportsArithemetic = TransferSizes(1, beatBytes), + supportsLogical = TransferSizes(1, beatBytes), + supportsGet = TransferSizes(1, beatBytes), + supportsPutFull = TransferSizes(1, beatBytes), + supportsPutPartial = TransferSizes(1, beatBytes), + supportsHint = TransferSizes(1, beatBytes), + fifoId = Some(0))) + + lazy val module = new LazyModuleImp(this) { + val (tl, edge) = node.in(0) + } + } + +The ``makeManagerNode`` method takes two arguments. The first is ``beatBytes``, +which is the physical width of the TileLink interface in bytes. The second +is a TLManagerParameters object. + +The only required argument for ``TLManagerParameters`` is the ``address``, +which is the set of address ranges that this manager will serve. +This information is used to route requests from the clients. + +The second argument is ``resources``, which is usually retrieved from a +``Device`` object. In this case, we use a ``SimpleDevice`` object. +This argument is necessary if you want to add an entry to the DeviceTree in +the BootROM so that it can be read by a Linux driver. The two arguments to +``SimpleDevice`` are the name and compatibility list for the device tree +entry. For this manager, then, the device tree entry would look like + +.. code-block:: text + + L12: my-device@20000 { + compatible = "tutorial,my-device0"; + reg = <0x20000 0x1000>; + }; + +The next argument is ``regionType``, which gives some information about +the caching behavior of the manager. There are seven region types, listed below: + +1. ``CACHED`` - An intermediate agent may have cached a copy of the region for you. +2. ``TRACKED`` - The region may have been cached by another master, but coherence is being provided. +3. ``UNCACHED`` - The region has not been cached yet, but should be cached when possible. +4. ``IDEMPOTENT`` - Gets return most recently put content, but content should not be cached. +5. ``VOLATILE`` - Content may change without a put, but puts and gets have no side effects. +6. ``PUT_EFFECTS`` - Puts produce side effects and so must not be combined/delayed. +7. ``GET_EFFECTS`` - Gets produce side effects and so must not be issued speculatively. + +Next is the ``executable`` argument, which determines if the CPU is allowed to +fetch instructions from this manager. By default it is false, which is what +most MMIO peripherals should set it to. + +The next six arguments start with ``support`` and determine the different +A channel message types that the manager can accept. The definitions of the +message types are explained in :ref:`TileLink Edge Object Methods`. +The ``TransferSizes`` case class specifies the range of logical sizes (in bytes) +that the manager can accept for the particular message type. This is an inclusive +range and all logical sizes must be powers of two. So in this case, the manager +can accept requests with sizes of 1, 2, 4, or 8 bytes. + +The final argument shown here is the ``fifoId`` setting, which determines +which FIFO domain (if any) the manager is in. If this argument is set to ``None`` +(the default), the manager will not guarantee any ordering of the responses. +If the ``fifoId`` is set, it will share a FIFO domain with all other managers +that specify the same ``fifoId``. This means that client requests sent to +that FIFO domain will see responses in the same order. + +Register Node +------------- + +While you can directly specify a manager node and write all of the logic +to handle TileLink requests, it is usually much easier to use a register node. +This type of node provides a ``regmap`` method that allows you to specify +control/status registers and automatically generates the logic to handle the +TileLink protocol. More information about how to use register nodes can be +found in :ref:`Register Router`. + +Identity Node +------------- + +Unlike the previous node types, which had only inputs or only outputs, the +identity node has both. As its name suggests, it simply connects the inputs +to the outputs unchanged. This node is mainly used to combine multiple +nodes into a single node with multiple edges. For instance, say we have two +client lazy modules, each with their own client node. + +.. code-block:: scala + + class MyClient1(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeClientNode("my-client1", IdRange(0, 1)) + + // ... + } + + class MyClient2(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeClientNode("my-client2", IdRange(0, 1)) + + // ... + } + +Now we instantiate these two clients in another lazy module and expose their +nodes as a single node. + +.. code-block:: scala + + class MyClientGroup(implicit p: Parameters) extends LazyModule { + val client1 = LazyModule(new MyClient1) + val client2 = LazyModule(new MyClient2) + val node = TLIdentityNode() + + node := client1.node + node := client2.node + + // ... + } + +We can also do the same for managers. + +.. code-block:: scala + + class MyManager1(beatBytes: Int)(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeManagerNode(beatBytes, TLManagerParameters( + address = Seq(AddressSet(0x0, 0xfff)))) + // ... + } + + class MyManager2(beatBytes: Int)(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeManagerNode(beatBytes, TLManagerParameters( + address = Seq(AddressSet(0x1000, 0xfff)))) + // ... + } + + class MyManagerGroup(beatBytes: Int)(implicit p: Parameters) extends LazyModule { + val man1 = LazyModule(new MyManager1(beatBytes)) + val man2 = LazyModule(new MyManager2(beatBytes)) + val node = TLIdentityNode() + + man1.node := node + man2.node := node + } + +If we want to connect the client and manager groups together, we can now do this. + +.. code-block:: scala + + class ClientManagerComplex(implicit p: Parameters) extends LazyModule { + val client = LazyModule(new MyClientGroup) + val manager = LazyModule(new MyManagerGroup(8)) + + manager.node :=* client.node + } + +The meaning of the ``:=*`` operator is explained in more detail in the +:ref:`Diplomacy Connectors` section. In summary, it connects two nodes together +using multiple edges. The edges in the identity node are assigned in order, +so in this case ``client1.node`` will eventually connect to ``manager1.node`` +and ``client2.node`` will connect to ``manager2.node``. + +The number of inputs to an identity node should match the number of outputs. +A mismatch will cause an elaboration error. + +Adapter Node +------------ + +Like the identity node, the adapter node takes some number of inputs and +produces the same number of outputs. However, unlike the identity node, the +adapter node does not simply pass the connections through unchanged. +It can change the logical and physical interfaces between input and output and +rewrite messages going through. RocketChip provides a library of adapters, +which are catalogued in :ref:`Diplomatic Widgets`. + +You will rarely need to create an adapter node yourself, but the invocation is +as follows. + +.. code-block:: scala + + val node = TLAdapterNode( + clientFn = { cp => + // .. + }, + managerFn = { mp => + // .. + }) + +The ``clientFn`` is a function that takes the ``TLClientPortParameters`` of +the input as an argument and returns the corresponding parameters for the +output. The ``managerFn`` takes the ``TLManagerPortParameters`` of the output +as an argument and returns the corresponding parameters for the input. + +Nexus Node +---------- + +The nexus node is similar to the adapter node in that it has a different +output interface than input interface. But it can also have a different +number of inputs than it does outputs. This node type is mainly used by +the ``TLXbar`` widget, which provides a TileLink crossbar generator. You will +also likely not need to define this node type manually, but its invocation is +as follows. + +.. code-block:: scala + + val node = TLNexusNode( + clientFn = { seq => + // .. + }, + managerFn = { seq => + // .. + }) + +This has similar arguments as the adapter node's constructor, but instead of +taking single parameters objects as arguments and returning single objects +as results, the functions take and return sequences of parameters. And as you +might expect, the size of the returned sequence need not be the same size as +the input sequence. diff --git a/docs/TileLink-Diplomacy-Reference/Register-Router.rst b/docs/TileLink-Diplomacy-Reference/Register-Router.rst new file mode 100644 index 00000000..d1efa49f --- /dev/null +++ b/docs/TileLink-Diplomacy-Reference/Register-Router.rst @@ -0,0 +1,2 @@ +Register Router +=============== diff --git a/docs/TileLink-Diplomacy-Reference/Widgets.rst b/docs/TileLink-Diplomacy-Reference/Widgets.rst new file mode 100644 index 00000000..31b210b2 --- /dev/null +++ b/docs/TileLink-Diplomacy-Reference/Widgets.rst @@ -0,0 +1,2 @@ +Diplomatic Widgets +================== diff --git a/docs/TileLink-Diplomacy-Reference/index.rst b/docs/TileLink-Diplomacy-Reference/index.rst new file mode 100644 index 00000000..abf797c7 --- /dev/null +++ b/docs/TileLink-Diplomacy-Reference/index.rst @@ -0,0 +1,29 @@ +TileLink and Diplomacy Reference +================================ + +TileLink is the cache coherence and memory protocol used by RocketChip and +other Chipyard generators. It is how different modules like caches, memories, +peripherals, and DMA devices communicate with each other. + +TileLink is built on top of diplomacy, a framework for exchanging +configuration information among Chisel generators in a two-phase elaboration +scheme. + +A brief overview of how to connect simple TileLink widgets can be found +in the :ref:`Adding-an-Accelerator` section. This section will provide a +detailed reference for the TileLink and Diplomacy functionality provided by +RocketChip. + +A detailed specification of the TileLink 1.7 protocol can be found on the +`SiFive website `. + + +.. toctree:: + :maxdepth: 2 + :caption: Reference + + NodeTypes + Diplomacy-Connectors + EdgeFunctions + Register-Router + Widgets diff --git a/docs/index.rst b/docs/index.rst index b9174005..eff043df 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -30,6 +30,7 @@ New to Chipyard? Jump to the :ref:`Chipyard Basics` page for more info. Advanced-Usage/index + TileLink-Diplomacy-Reference/index Indices and tables From 0e8dc833b8fbe7d2ea9670d7144f348dcdf376f8 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Sat, 7 Sep 2019 22:34:08 -0700 Subject: [PATCH 61/91] write Register Router documentation --- .../Register-Router.rst | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/docs/TileLink-Diplomacy-Reference/Register-Router.rst b/docs/TileLink-Diplomacy-Reference/Register-Router.rst index d1efa49f..2e713e17 100644 --- a/docs/TileLink-Diplomacy-Reference/Register-Router.rst +++ b/docs/TileLink-Diplomacy-Reference/Register-Router.rst @@ -1,2 +1,200 @@ Register Router =============== + +Memory-mapped devices generally follow a common pattern. They expose a set +of registers to the CPUs. By writing to a register, the CPU can change the +device's settings or send a command. By reading from a register, the CPU can +query the device's state or retrieve results. + +While designers can manually instantiate a manager node and write the logic +for exposing registers themselves, it's much easier to use RocketChip's +``regmap`` interface, which can generate most of the glue logic. + +For TileLink devices, you can use the ``regmap`` interface by extending +the ``TLRegisterRouter`` class, as shown in :ref:`Adding An Accelerator/Device`, +or you can create a regular LazyModule and instantiate a ``TLRegisterNode``. +This section will focus on the second method. + +Basic Usage +----------- + +.. code-block:: scala + + import chisel3._ + import chisel3.util._ + import freechips.rocketchip.config.Parameters + import freechips.rocketchip.diplomacy.{SimpleDevice, AddressSet} + import freechips.rocketchip.tilelink.TLRegisterNode + + class MyDeviceController(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice("my-device", Seq("tutorial,my-device0")) + val node = TLRegisterNode( + address = Seq(AddressSet(0x10019000, 0xfff)), + device = device, + beatBytes = 8, + concurrency = 1) + + lazy val module = new LazyModuleImp(this) { + val bigReg = RegInit(0.U(64.W)) + val mediumReg = RegInit(0.U(32.W)) + val smallReg = RegInit(0.U(16.W)) + + val tinyReg0 = RegInit(0.U(4.W)) + val tinyReg1 = RegInit(0.U(4.W)) + + node.regmap( + 0x00 -> Seq(RegField(64, bigReg)), + 0x08 -> Seq(RegField(32, mediumReg)), + 0x0C -> Seq(RegField(16, smallReg)), + 0x0E -> Seq( + RegField(4, tinyReg0), + RegField(4, tinyReg1))) + } + } + +The code example above shows a simple lazy module that uses the ``TLRegisterNode`` +to memory map hardware registers of different sizes. The constructor has +two required arguments: ``address``, which is the base address of the registers, +and ``device``, which is the device tree entry. There are also two optional +arguments. The ``beatBytes`` argument is the interface width in bytes. +The default value is 4 bytes. The ``concurrency`` argument is the size of the +internal queue for TileLink requests. By default, this value is 0, which means +there will be no queue. This value must be greater than 0 if you wish to +decoupled requests and responses for register accesses. This is discussed +in :ref:`Using Functions`. + +The main way to interact with the node is to call the ``regmap`` method, which +takes a sequence of pairs. The first element of the pair is an offset from the +base address. The second is a sequence of ``RegField`` objects, each of +which maps a different register. The ``RegField`` constructor takes two +arguments. The first argument is the width of the register in bits. +The second is the register itself. + +Since the argument is a sequence, you can associate multiple ``RegField`` +objects with an offset. If you do, the registers are read or written in parallel +when the offset is accessed. The registers are in little endian order, so the +first register in the list corresponds to the least significant bits in the +value written. In this example, if the CPU wrote to offset 0x0E with the value +0xAB, ``smallReg0`` will get the value 0xB and ``smallReg1`` would get 0xA. + +Decoupled Interfaces +-------------------- + +Sometimes you may want to do something other than read and write from a hardware +register. The ``RegField`` interface also provides support for reading +and writing ``DecoupledIO`` interfaces. For instance, you can implement a +hardware FIFO like so. + +.. code-block:: scala + + // 4-entry 64-bit queue + val queue = Module(new Queue(UInt(64.W), 4)) + + node.regmap( + 0x00 -> Seq(RegField(64, queue.io.deq, queue.io.enq))) + +This variant of the ``RegField`` constructor takes three arguments instead of +two. The first argument is still the bit width. The second is the decoupled +interface to read from. The third is the decoupled interface to write to. +In this example, writing to the "register" will push the data into the queue +and reading from it will pop data from the queue. + +You need not specify both read and write for a register. You can also create +read-only or write-only registers. So for the previous example, if you wanted +enqueue and dequeue to use different addresses, you could write the following. + +.. code-block:: scala + + node.regmap( + 0x00 -> Seq(RegField.r(64, queue.io.deq)), + 0x08 -> Seq(RegField.w(64, queue.io.enq))) + +The read-only register function can also be used to read signals +that aren't registers. + +.. code-block:: scala + + val constant = 0xf00d.U + + node.regmap( + 0x00 -> Seq(RegField.r(8, constant))) + +Using Functions +--------------- + +You can also create registers using functions. Say, for instance, that you +want to create a counter that gets incremented on a write and decremented on +a read. + +.. code-block:: scala + + val counter = RegInit(0.U(64.W)) + + def readCounter(ready: Bool): (Bool, UInt) = { + when (ready) { counter := counter - 1.U } + (true.B, counter) + } + + def writeCounter(valid: Bool, bits: UInt): Bool = { + when (valid) { counter := counter + 1.U } + // Ignore bits + true.B + } + + node.regmap( + 0x00 -> Seq(RegField.r(64, readCounter(_))), + 0x08 -> Seq(RegField.w(64, writeCounter(_, _)))) + +The functions here are essentially the same as a decoupled interface. +The read function gets passed the ``ready`` signal and returns the +``valid`` and ``bits`` signals. The write function gets passed ``valid` and +``bits`` and returns ``ready``. + +You can also pass functions that decouple the read/write request and response. +The request will appear as a decoupled input and the response as a decoupled +output. So for instance, if we wanted to do this for the previous example. + +.. code-block:: scala + + val counter = RegInit(0.U(64.W)) + + def readCounter(ivalid: Bool, oready: Bool): (Bool, Bool, UInt) = { + val responding = RegInit(false.B) + + when (ivalid && !responding) { responding := true.B } + + when (responding && oready) { + counter := counter - 1.U + responding := false.B + } + + (!responding, responding, counter) + } + + def writeCounter(ivalid: Bool, bits: UInt, oready: Bool): (Bool, Bool) = { + val responding = RegInit(false.B) + + when (ivalid && !responding) { responding := true.B } + + when (responding && oready) { + counter := counter + 1.U + responding := false.B + } + + (!responding, responding) + } + + node.regmap( + 0x00 -> Seq(RegField.r(64, readCounter(_, _))), + 0x08 -> Seq(RegField.w(64, writeCounter(_, _, _)))) + +In each function, we set up a state variable ``responding``. The function +is ready to take requests when this is false and is sending a response when +this is true. + +In this variant, both read and write take an input valid and return an +output ready. The only different is that bits is an input for read and an +output for write. + +In order to use this variant, you need to set ``concurrency`` to a value +larger than 0. From 334e443003aff8fff857b033e028bb696f60ae90 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Sun, 8 Sep 2019 16:19:08 -0700 Subject: [PATCH 62/91] add part about AXI4RegisterNode --- .../Register-Router.rst | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/TileLink-Diplomacy-Reference/Register-Router.rst b/docs/TileLink-Diplomacy-Reference/Register-Router.rst index 2e713e17..4f129e47 100644 --- a/docs/TileLink-Diplomacy-Reference/Register-Router.rst +++ b/docs/TileLink-Diplomacy-Reference/Register-Router.rst @@ -198,3 +198,46 @@ output for write. In order to use this variant, you need to set ``concurrency`` to a value larger than 0. + +Register Routers for Other Protocols +------------------------------------ + +One useful feature of the register router interface is that you can easily +change the protocol being used. For instance, in the first example in +:ref:`Basic Usage`, you could simply change the ``TLRegisterNode`` to +and ``AXI4RegisterNode``. + +.. code-block:: scala + + import chisel3._ + import chisel3.util._ + import freechips.rocketchip.config.Parameters + import freechips.rocketchip.diplomacy.{SimpleDevice, AddressSet} + import freechips.rocketchip.amba.axi4.AXI4RegisterNode + + class MyAXI4DeviceController(implicit p: Parameters) extends LazyModule { + val node = AXI4RegisterNode( + address = Seq(AddressSet(0x10019000, 0xfff)), + beatBytes = 8, + concurrency = 1) + + lazy val module = new LazyModuleImp(this) { + val bigReg = RegInit(0.U(64.W)) + val mediumReg = RegInit(0.U(32.W)) + val smallReg = RegInit(0.U(16.W)) + + val tinyReg0 = RegInit(0.U(4.W)) + val tinyReg1 = RegInit(0.U(4.W)) + + node.regmap( + 0x00 -> Seq(RegField(64, bigReg)), + 0x08 -> Seq(RegField(32, mediumReg)), + 0x0C -> Seq(RegField(16, smallReg)), + 0x0E -> Seq( + RegField(4, tinyReg0), + RegField(4, tinyReg1))) + } + } + +Other than the fact that AXI4 nodes don't take a ``device`` argument, +everything else is unchanged. From e9bce0fc3d49e291c9276e3aae1ed164f21bb914 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Sun, 8 Sep 2019 16:19:21 -0700 Subject: [PATCH 63/91] clarification of AddressRange arguments --- .../NodeTypes.rst | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst index ace3d310..d066c7d0 100644 --- a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst +++ b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst @@ -29,7 +29,7 @@ object from testchipip like so: name = "my-client", sourceId = IdRange(0, 4), requestFifo = true, - visibility = Seq(AddressSet(0, 0xffff)))) + visibility = Seq(AddressSet(0x10000, 0xffff)))) lazy val module = new LazyModuleImp(this) { val (tl, edge) = node.out(0) @@ -53,13 +53,13 @@ If it is set to true, the client will request that downstream managers that support it send responses in FIFO order (that is, in the same order the corresponding requests were sent). -The ``visibility`` argument specifies the address ranges that the client -will access. By default it is set to include all addresses. In this example, -we set it to contain a single address range ``AddressSet(0, 0xffff)``, which -means that the client will only access addresses in this range. Clients -normally do not specify this, but it can help downstream crossbar generators -optimize the hardware by not arbitrating the client to managers with address -ranges that don't overlap with its visibility. +The ``visibility`` argument specifies the address ranges that the client will +access. By default it is set to include all addresses. In this example, we set +it to contain a single address range ``AddressSet(0x10000, 0xffff)``, which +means that the client will only be able to access addresses from 0x10000 to +0x1ffff. normally do not specify this, but it can help downstream crossbar +generators optimize the hardware by not arbitrating the client to managers with +address ranges that don't overlap with its visibility. Inside your lazy module implementation, you can call ``node.out`` to get a list of bundle/edge pairs. If you used the TLHelper, you only specified a @@ -116,7 +116,11 @@ is a TLManagerParameters object. The only required argument for ``TLManagerParameters`` is the ``address``, which is the set of address ranges that this manager will serve. -This information is used to route requests from the clients. +This information is used to route requests from the clients. In this example, +the manager will only take requests for addresses from 0x20000 to 0x20fff. +The second argument in ``AddressSet`` is a mask, not a size. +You should generally set it to be one less than a power of two. Otherwise, +the addressing behavior may not be what you expect. The second argument is ``resources``, which is usually retrieved from a ``Device`` object. In this case, we use a ``SimpleDevice`` object. From 753788ad67e543f5af97b815c19797ef9cb40a62 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Sun, 8 Sep 2019 21:30:47 -0700 Subject: [PATCH 64/91] add documentation on TileLink/AXI4 diplomatic widgets --- docs/TileLink-Diplomacy-Reference/Widgets.rst | 465 ++++++++++++++++++ 1 file changed, 465 insertions(+) diff --git a/docs/TileLink-Diplomacy-Reference/Widgets.rst b/docs/TileLink-Diplomacy-Reference/Widgets.rst index 31b210b2..a5a171d4 100644 --- a/docs/TileLink-Diplomacy-Reference/Widgets.rst +++ b/docs/TileLink-Diplomacy-Reference/Widgets.rst @@ -1,2 +1,467 @@ Diplomatic Widgets ================== + +RocketChip provides a library of diplomatic TileLink and AXI4 widgets. +The most commonly used widgets are documented here. The TileLink widgets +are available from ``freechips.rocketchip.tilelink`` and the AXI4 widgets +from ``freechips.rocketchip.amba.axi4``. + +TLBuffer +-------- + +A widget for buffering TileLink transactions. It simply instantiates queues +for each of the 2 (or 5 for TL-C) decoupled channels. To configure the queue +for each channel, you pass the constructor a +``freechips.rocketchip.diplomacy.BufferParams`` object. The arguments for +this case class are: + + - ``depth: Int`` - The number of entries in the queue + - ``flow: Boolean`` - If true, combinationally couple the valid signals so + that an input can be consumed on the same cycle it is enqueued. + - ``pipe: Boolean`` - If true, combinationally couple the ready signals so + that single-entry queues can run at full rate. + +There is an implicit conversion from ``Int`` available. If you pass an +integer instead of a BufferParams object, the queue will be the depth +given in the integer and ``flow`` and ``pipe`` will both be false. + +You can also use one of the predefined BufferParams objects. + + - ``BufferParams.default`` = ``BufferParams(2, false, false)`` + - ``BufferParams.none`` = ``BufferParams(0, false, false)`` + - ``BufferParams.flow`` = ``BufferParams(1, true, false)`` + - ``BufferParams.pipe`` = ``BufferParams(1, false, true)`` + +**Arguments:** + +There are four constructors available with zero, one, two, or five arguments. + +The zero-argument constructor uses ``BufferParams.default`` for all of the +channels. + +The single-argument constructor takes a ``BufferParams`` object to use for all +channels. + +The arguments for the two-argument constructor are: + + - ``ace: BufferParams`` - Parameters to use for the A, C, and E channels. + - ``bd: BufferParams`` - Parameters to use for the B and D channels + +The arguments for the five-argument constructor are + + - ``a: BufferParams`` - Buffer parameters for the A channel + - ``b: BufferParams`` - Buffer parameters for the B channel + - ``c: BufferParams`` - Buffer parameters for the C channel + - ``d: BufferParams`` - Buffer parameters for the D channel + - ``e: BufferParams`` - Buffer parameters for the E channel + +**Example Usage:** + +.. code-block:: scala + + // Default settings + manager0.node := TLBuffer() := client0.node + + // Using implicit conversion to make buffer with 8 queue entries per channel + manager1.node := TLBuffer(8) := client1.node + + // Use default on A channel but pipe on D channel + manager2.node := TLBuffer(BufferParams.default, BufferParams.pipe) := client2.node + + // Only add queues for the A and D channel + manager3.node := TLBuffer( + BufferParams.default, + BufferParams.none, + BufferParams.none, + BufferParams.default, + BufferParams.none) := client3.node + +AXI4Buffer +---------- + +Similar to the :ref:`TLBuffer`, but for AXI4. It also takes ``BufferParams`` objects +as arguments. + +**Arguments:** + +Like TLBuffer, AXI4Buffer has zero, one, two, and five-argument constructors. + +The zero-argument constructor uses the default BufferParams for all channels. + +The one-argument constructor uses the provided BufferParams for all channels. + +The two-argument constructor has the following arguments. + + - ``aw: BufferParams`` - Buffer parameters for the "ar", "aw", and "w" channels. + - ``br: BufferParams`` - Buffer parameters for the "b", and "r" channels. + +The five-argument constructor has the following arguments + + - ``aw: BufferParams`` - Buffer parameters for the "ar" channel + - ``w: BufferParams`` - Buffer parameters for the "w" channel + - ``b: BufferParams`` - Buffer parameters for the "b" channel + - ``ar: BufferParams`` - Buffer parameters for the "ar" channel + - ``r: BufferParams`` - Buffer parameters for the "r" channel + +**Example Usage:** + +.. code-block:: scala + + // Default settings + slave0.node := AXI4Buffer() := master0.node + + // Using implicit conversion to make buffer with 8 queue entries per channel + slave1.node := AXI4Buffer(8) := master1.node + + // Use default on aw/w/ar channel but pipe on b/r channel + slave2.node := AXI4Buffer(BufferParams.default, BufferParams.pipe) := master2.node + + // Single-entry queues for aw, b, and ar but two-entry queues for w and r + slave3.node := AXI4Buffer(1, 2, 1, 1, 2) := master3.node + +AXI4UserYanker +-------------- + +This widget takes an AXI4 port that has a user field and turns it into +one without a user field. The values of the user field from input AR and AW +requests is kept in internal queues associated with the ARID/AWID, which is +then used to associate the correct user field to the responses. + +**Arguments:** + + - ``capMaxFlight: Option[Int]`` - (optional) An option which can hold the + number of requests that can be inflight for each ID. If ``None`` (the default), + the UserYanker will support the maximum number of inflight requests. + +**Example Usage:** + +.. code-block:: scala + + nouser.node := AXI4UserYanker(Some(1)) := hasuser.node + +AXI4Deinterleaver +----------------- + +Multi-beat AXI4 read responses for different IDs can potentially be interleaved. +This widget reorders read responses from the slave so that all of the beats +for a single transaction are consecutive. + +**Arguments:** + + - ``maxReadBytes: Int`` - The maximum number of bytes that can be read + in a single transaction. + +**Example Usage:** + +.. code-block:: scala + + interleaved.node := AXI4Deinterleaver() := consecutive.node + +TLFragmenter +------------ + +The TLFragmenter widget shrinks the maximum logical transfer size of the +TileLink interface by breaking larger transactions into multiple smaller +transactions. + +**Arguments:** + + - ``minSize: Int`` - Minimum size of transfers supported by all outward managers. + - ``maxSize: Int`` - Maximum size of transfers supported after the Fragmenter is applied. + - ``alwaysMin: Boolean`` - (optional) Fragment all requests down to minSize (else fragment to maximum supported by manager). (default: false) + - ``earlyAck: EarlyAck.T`` - (optional) Should a multibeat Put be acknowledged on the first beat or last beat? + Possible values (default: ``EarlyAck.None``): + + - ``EarlyAck.AllPuts`` - always acknowledge on first beat. + - ``EarlyAck.PutFulls`` - acknowledge on first beat if PutFull, otherwise acknowledge on last beat. + - ``EarlyAck.None`` - always acknowledge on last beat. + + - ``holdFirstDenied: Boolean`` - (optional) Allow the Fragmenter to unsafely combine multibeat Gets by taking the first denied for the whole burst. (default: false) + +**Example Usage:** + +.. code-block:: scala + + val beatBytes = 8 + val blockBytes = 64 + + single.node := TLFragmenter(beatBytes, blockBytes) := multi.node + + axi4lite.node := AXI4Fragmenter() := axi4full.node + +**Additional Notes** + + - TLFragmenter modifies: PutFull, PutPartial, LogicalData, Get, Hint + - TLFragmenter passes: ArithmeticData (truncated to minSize if alwaysMin) + - TLFragmenter cannot modify acquire (could livelock); thus it is unsafe to put caches on both sides + +AXI4Fragmenter +-------------- + +The AXI4Fragmenter is similar to the :ref:`TLFragmenter`, except it can only +break multi-beat AXI4 transactions into single-beat transactions. This +effectively serves as an AXI4 to AXI4-Lite converter. The constructor for this +widget does not take any arguments. + +**Example Usage:** + +.. code-block:: scala + + axi4lite.node := AXI4Fragmenter() := axi4full.node + +TLSourceShrinker +---------------- + +The number of source IDs that a manager sees is usually computed based on the +clients that connect to it. In some cases, you may wish to fix the +number of source IDs. For instance, you might do this if you wish to export +the TileLink port to a Verilog black box. This will pose a problem, however, +if the clients require a larger number of source IDs. In this situation, +you will want to use a TLSourceShrinker. + +**Arguments:** + + - ``maxInFlight: Int`` - The maximum number of source IDs that will be sent + from the TLSourceShrinker to the manager. + +**Example Usage:** + +.. code-block:: scala + + // client.node may have >16 source IDs + // manager.node will only see 16 + manager.node := TLSourceShrinker(16) := client.node + +AXI4IdIndexer +------------- + +The AXI4 equivalent of :ref:`TLSourceShrinker`. This limits the number of +AWID/ARID bits in the slave AXI4 interface. Useful for connecting to external +or black box AXI4 ports. + +**Arguments:** + + - ``idBits: Int`` - The number of ID bits on the slave interface. + +**Example Usage:** + +.. code-block:: scala + + // master.node may have >16 unique IDs + // slave.node will only see 4 ID bits + slave.node := AXI4IdIndexer(4) := master.node + +**Notes:** + +The AXI4IdIndexer will create a ``user`` field on the slave interface, as it +stores the ID of the master requests in this field. If connecting to an AXI4 +interface that doesn't have a ``user`` field, you'll need to use the :ref:`AXI4UserYanker`. + +TLWidthWidget +------------- + +This widget changes the physical width of the TileLink interface. The width +of a TileLink interface is configured by managers, but sometimes you want +the client to see a particular width. + +**Arguments:** + + - ``innerBeatBytes: Int`` - The physical width (in bytes) seen by the client + +**Example Usage:** + +.. code-block:: + + // Assume the manager node sets beatBytes to 8 + // With WidthWidget, client sees beatBytes of 4 + manager.node := TLWidthWidget(4) := client.node + +TLFIFOFixer +----------- + +TileLink managers that declare a FIFO domain must ensure that all requests to +that domain from clients which have requested FIFO ordering see responses in +order. However, they can only control the ordering of their own responses, and +do not have control over how those responses interleave with responses from +other managers in the same FIFO domain. Responsibility for ensuring FIFO order +across managers goes to the TLFIFOFixer. + +**Arguments:** + + - ``policy: TLFIFOFixer.Policy`` - (optional) Which managers will the + TLFIFOFixer enforce ordering on? (default: ``TLFIFOFixer.all``) + +The possible values of ``policy`` are: + + - ``TLFIFOFixer.all`` - All managers (including those without a FIFO domain) + will have ordering guaranteed + - ``TLFIFOFixer.allFIFO`` - All managers that define a FIFO domain will have + ordering guaranteed + - ``TLFIFOFixer.allVolatile`` - All managers that have a RegionType of + ``VOLATILE``, ``PUT_EFFECTS``, or ``GET_EFFECTS`` will have ordering + guaranteed (see :ref:`Manager Node` for explanation of region types). + +TLXbar and AXI4Xbar +------------------- + +These are crossbar generators for TileLink and AXI4 which will route requests +from TL client / AXI4 master nodes to TL manager / AXI4 slave nodes based on +the addresses defined in the managers / slaves. Normally, these are constructed +without arguments. However, you can change the arbitration policy, which +determines which client ports get precedent in the arbiters. The default policy +is ``TLArbiter.roundRobin``, but you can change it to ``TLArbiter.lowestIndexFirst`` +if you want a fixed arbitration precedence. + +**Arguments:** + +All arguments are optional. + + - ``arbitrationPolicy: TLArbiter.Policy`` - The arbitration policy to use. + - ``maxFlightPerId: Int`` - (AXI4 only) The number of transactions with the + same ID that can be inflight at a time. (default: 7) + - ``awQueueDepth: Int`` - (AXI4 only) The depth of the write address queue. + (default: 2) + +**Example Usage:** + +.. code-block:: scala + + // Instantiate the crossbar lazy module + val tlBus = LazyModule(new TLXbar) + + // Connect a single input edge + tlBus.node := tlClient0.node + // Connect multiple input edges + tlBus.node :=* tlClient1.node + + // Connect a single output edge + tlManager0.node := tlBus.node + // Connect multiple output edges + tlManager1.node :*= tlBus.node + + // Instantiate a crossbar with lowestIndexFirst arbitration policy + // Yes, we still use the TLArbiter singleton even though this is AXI4 + val axiBus = LazyModule(new AXI4Xbar(TLArbiter.lowestIndexFirst)) + + // The connections work the same as TL + axiBus.node := axiClient0.node + axiBus.node :=* axiClient1.node + axiManager0.node := axiBus.node + axiManager1.node :*= axiBus.node + + + +TLToAXI4 and AXI4ToTL +--------------------- + +These are converters between the TileLink and AXI4 protocols. TLToAXI4 +takes a TileLink client and connects to an AXI4 slave. AXI4ToTL takes an +AXI4 master and connects to a TileLink manager. Generally you don't want to +override the default arguments of the constructors for these widgets. + +**Example Usage:** + +.. code-block:: scala + + axi4slave.node := + AXI4UserYanker() := + AXI4Deinterleaver(64) := + TLToAXI4() := + tlclient.node + + tlmanager.node := + AXI4ToTL() := + AXI4UserYanker() := + AXI4Fragmenter() := + axi4master.node + +You will need to add an :ref:`AXI4Deinterleaver` after the TLToAXI4 converter +because it cannot deal with interleaved read responses. The TLToAXI4 converter +also uses the AXI4 user field to store some information, so you will need an +:ref:`AXI4UserYanker` if you want to connect to an AXI4 port without user +fields. + +Before you connect an AXI4 port to the AXI4ToTL widget, you will need to +add an :ref:`AXI4Fragmenter` and :ref:`UserYanker` because the converter cannot +deal with multi-beat transactions or user fields. + +TLROM +------ + +The TLROM widget provides a read-only memory that can be accessed using +TileLink. Note: this widget is in the ``freechips.rocketchip.devices.tilelink`` +package, not the ``freechips.rocketchip.tilelink`` package like the others. + +**Arguments:** + + - ``base: BigInt`` - The base address of the memory + - ``size: Int`` - The size of the memory in bytes + - ``contentsDelayed: => Seq[Byte]`` - A function which, when called generates + the byte contents of the ROM. + - ``executable: Boolean`` - (optional) Specify whether the CPU can fetch + instructions from the ROM (default: ``true``). + - ``beatBytes: Int`` - (optional) The width of the interface in bytes. + (default: 4). + - ``resources: Seq[Resource]`` - (optional) Sequence of resources to add to + the device tree. + +**Example Usage:** + +.. code-block:: scala + + val rom = LazyModule(new TLROM( + base = 0x100A0000, + size = 64, + contentsDelayed = Seq.tabulate(64) { i => i.toByte }, + beatBytes = 8)) + rom.node := TLFragmenter(8, 64) := client.node + +**Supported Operations:** + +The TLROM only supports single-beat reads. If you want to perform multi-beat +reads, you should attach a TLFragmenter in front of the ROM. + +TLRAM and AXI4RAM +----------------- + +The TLRAM and AXI4RAM widgets provide read-write memories implemented as SRAMs. + +**Arguments:** + + - ``address: AddressSet`` - The address range that this RAM will cover. + - ``cacheable: Boolean`` - (optional) Can the contents of this RAM be cached. + (default: ``true``) + - ``executable: Boolean`` - (optional) Can the contents of this RAM be fetched + as instructions. (default: ``true``) + - ``beatBytes: Int`` - (optional) Width of the TL/AXI4 interface in bytes. + (default: 4) + - ``atomics: Boolean`` - (optional, TileLink only) Does the RAM support + atomic operations? (default: ``false``) + +**Example Usage:** + +.. code-block:: scala + + val xbar = LazyModule(new TLXbar) + + val tlram = LazyModule(new TLRAM( + address = AddressSet(0x1000, 0xfff))) + + val axiram = LazyModule(new AXI4RAM( + address = AddressSet(0x2000, 0xfff))) + + tlram.node := xbar.node + axiram := TLToAXI4() := xbar.node + +**Supported Operations:** + +TLRAM only supports single-beat TL-UL requests. If you set ``atomics`` to true, +it will also support Logical and Arithmetic operations. Use a ``TLFragmenter`` +if you want multi-beat reads/writes. + +AXI4RAM only supports AXI4-Lite operations, so multi-beat reads/writes and +reads/writes smaller than full-width are not supported. Use an ``AXI4Fragmenter`` +if you want to use the full AXI4 protocol. + + + From a4371fa9171d0ac3160455c8981d38c630d73b01 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 9 Sep 2019 18:07:08 -0700 Subject: [PATCH 65/91] add section on SoC boot process --- docs/Customization/Boot-Process.rst | 75 +++++++++++++++++++++++++++++ docs/Customization/index.rst | 1 + 2 files changed, 76 insertions(+) create mode 100644 docs/Customization/Boot-Process.rst diff --git a/docs/Customization/Boot-Process.rst b/docs/Customization/Boot-Process.rst new file mode 100644 index 00000000..df7e6931 --- /dev/null +++ b/docs/Customization/Boot-Process.rst @@ -0,0 +1,75 @@ +Chipyard Boot Process +======================= + +This section will describe in detail the process by which a Chipyard-based +SoC boots a Linux kernel and the changes you can make to customize this process. + +BootROM and RISC-V Frontend Server +---------------------------------- + +The first instructions to run when the SoC is powered on are those stored in +the BootROM. The assembly for the BootROM code is located in +`generators/testchipip/src/main/resources/testchipip/bootrom/bootrom.S `_. +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 +also point the generator to a different bootrom image by overriding the +``BootROMParams`` key in the configuration. + +.. code-block:: scala + + class WithMyBootROM extends Config((site, here, up) => { + case BootROMParams => + BootROMParams(contentFileName = "/path/to/your/bootrom.img") + }) + +The default bootloader simply loops on a wait-for-interrupt (WFI) instruction +as the RISC-V frontend-server (FESVR) loads the actual program. +FESVR is a program that runs on the host CPU and can read/write arbitrary +parts of the target system memory using the Tethered Serial Interface (TSI). + +FESVR uses TSI to load a baremetal executable or second-stage bootloader into +the SoC memory. In :ref:`Software RTL Simulation`, this will be the binary you +pass to the simulator. Once it is finished loading the program, FESVR will +write to the software interrupt register for CPU 0, which will bring CPU 0 +out of its WFI loop. Once it receives the interrupt, CPU 0 will write to +the software interrupt registers for the other CPUs in the system and then +jump to the beginning of DRAM to execute the first instruction of the loaded +executable. The other CPUs will be woken up by the first CPU and also jump +to the beginning of DRAM. + +The executable loaded by FESVR should have memory locations designated +as *tohost* and *fromhost*. FESVR uses these memory locations to communicate +with the executable once it is running. The executable uses *tohost* to send +commands to FESVR for things like printing to the console, +proxying system calls, and shutting down the SoC. The *fromhost* register is +used to send back responses for *tohost* commands and for sending console +input. + +The Berkeley Boot Loader and RISC-V Linux +----------------------------------------- + +For baremetal programs, the story ends here. The loaded executable will run in +machine mode until it sends a command through the *tohost* register telling the +FESVR to power off the SoC. + +However, for booting the Linux Kernel, you will need to use a second-stage +bootloader called the Berkeley Boot Loader, or BBL. This program reads the +device tree encoded in the boot ROM and transforms it into a format compatible +with the Linux kernel. It then sets up virtual memory and the interrupt +controller, loads the kernel, which is embedded in the bootloader binary as a +payload, and starts executing the kernel in supervisor mode. The bootloader is +also responsible for servicing machine-mode traps from the kernel and +proxying them over FESVR. + +Once BBL jumps into supervisor mode, the Linux kernel takes over and begins +its process. It eventually loads the ``init`` program and runs it in user +mode, thus starting userspace execution. + +The easiest way to build a BBL image that boots Linux is to use the FireMarshal +tool that lives in the `firesim-software `_ +repository. Directions on how to use FireMarshal can be found in the +`FireSim documentation `_. +Using FireMarshal, you can add custom kernel configurations and userspace software +to your workload. diff --git a/docs/Customization/index.rst b/docs/Customization/index.rst index 8d61801e..c0432e73 100644 --- a/docs/Customization/index.rst +++ b/docs/Customization/index.rst @@ -16,3 +16,4 @@ Hit next to get started! Heterogeneous-SoCs Adding-An-Accelerator Memory-Hierarchy + Boot-Process From 1fee2b12f1c08234268a0320b3c36294458577ed Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 9 Sep 2019 20:28:13 -0700 Subject: [PATCH 66/91] fix some language about TileLink's relationship to Diplomacy --- docs/TileLink-Diplomacy-Reference/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/TileLink-Diplomacy-Reference/index.rst b/docs/TileLink-Diplomacy-Reference/index.rst index abf797c7..af00323b 100644 --- a/docs/TileLink-Diplomacy-Reference/index.rst +++ b/docs/TileLink-Diplomacy-Reference/index.rst @@ -5,9 +5,9 @@ TileLink is the cache coherence and memory protocol used by RocketChip and other Chipyard generators. It is how different modules like caches, memories, peripherals, and DMA devices communicate with each other. -TileLink is built on top of diplomacy, a framework for exchanging -configuration information among Chisel generators in a two-phase elaboration -scheme. +RocketChip's TileLink implementation is built on top of Diplomacy, a framework +for exchanging configuration information among Chisel generators in a two-phase +elaboration scheme. A brief overview of how to connect simple TileLink widgets can be found in the :ref:`Adding-an-Accelerator` section. This section will provide a From fd5e0024a71fc81c5e53ee12e313b5424fb4f793 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 9 Sep 2019 20:28:30 -0700 Subject: [PATCH 67/91] capitalize Diplomacy when used as a name --- docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst | 4 ++-- docs/TileLink-Diplomacy-Reference/NodeTypes.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst b/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst index 2ff210de..9fc837fd 100644 --- a/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst +++ b/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst @@ -1,7 +1,7 @@ Diplomacy Connectors ==================== -Nodes in a diplomacy graph are connected to each other with edges. The diplomacy +Nodes in a Diplomacy graph are connected to each other with edges. The Diplomacy library provides four operators that can be used to form edges between nodes. := @@ -9,7 +9,7 @@ library provides four operators that can be used to form edges between nodes. This is the basic connection operator. It is the same syntax as the Chisel uni-directional connector, but it is not equivalent. This operator connects -diplomacy node, not Chisel bundles. +Diplomacy nodes, not Chisel bundles. The basic connection operator always creates a single edge between the two nodes. diff --git a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst index d066c7d0..79d8da74 100644 --- a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst +++ b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst @@ -38,7 +38,7 @@ object from testchipip like so: } } -The ``name`` argument identifies the node in the diplomacy graph. It is the +The ``name`` argument identifies the node in the Diplomacy graph. It is the only required argument for TLClientParameters. The ``sourceId`` argument specifies the range of source identifiers that this @@ -71,7 +71,7 @@ of TL-C) decoupled bundles corresponding to the TileLink channels. This is what you should connect your hardware logic to in order to actually send/receive TileLink messages. -The ``edge`` object represents the edge of the diplomacy graph. It contains +The ``edge`` object represents the edge of the Diplomacy graph. It contains some useful helper functions which will be documented in :ref:`TileLink Edge Object Methods`. From 646d7cba4c2469f7a35ad463bdaf3c15b1c4cdec Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 9 Sep 2019 22:47:23 -0700 Subject: [PATCH 68/91] use literalinclude directive to pull source directly from example package --- docs/Customization/Adding-An-Accelerator.rst | 144 +++++------------- .../example/src/main/scala/ConfigMixins.scala | 2 + generators/example/src/main/scala/PWM.scala | 8 + .../src/main/scala/RocketConfigs.scala | 2 + generators/example/src/main/scala/Top.scala | 2 + 5 files changed, 48 insertions(+), 110 deletions(-) diff --git a/docs/Customization/Adding-An-Accelerator.rst b/docs/Customization/Adding-An-Accelerator.rst index 336c9349..6a95fa84 100644 --- a/docs/Customization/Adding-An-Accelerator.rst +++ b/docs/Customization/Adding-An-Accelerator.rst @@ -66,50 +66,23 @@ 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``. -.. code-block:: scala - - case class PWMParams(address: BigInt, beatBytes: Int) - - trait PWMTLBundle extends Bundle { - val pwmout = Output(Bool()) - } - - trait PWMTLModule extends HasRegMap { - val io: PWMTLBundle - implicit val p: Parameters - def params: PWMParams - - val w = params.beatBytes * 8 - val period = Reg(UInt(w.W)) - val duty = Reg(UInt(w.W)) - val enable = RegInit(false.B) - - // ... Use the registers to drive io.pwmout ... - - regmap( - 0x00 -> Seq( - RegField(w, period)), - 0x04 -> Seq( - RegField(w, duty)), - 0x08 -> Seq( - RegField(1, enable))) - } - +.. 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. -.. code-block:: scala - - class PWMTL(c: PWMParams)(implicit p: Parameters) - extends TLRegisterRouter( - c.address, "pwm", Seq("ucbbar,pwm"), - beatBytes = c.beatBytes)( - new TLRegBundle(c, _) with PWMTLBundle)( - new TLRegModule(c, _, _) with PWMTLModule) +.. 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``. @@ -121,19 +94,10 @@ In the Rocket Chip cake, there are two kinds of traits: a ``LazyModule`` trait a 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. -.. code-block:: scala - - trait HasPeripheryPWM { this: BaseSubsystem => - implicit val p: Parameters - - private val address = 0x2000 - private val portName = "pwm" - - val pwm = LazyModule(new PWMTL(PWMParams(address, pbus.beatBytes))) - - pbus.toVariableWidthSlave(Some(portName)) { pwm.node } - } - +.. 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. @@ -143,30 +107,18 @@ The module implementation trait is where we instantiate our PWM module and conne 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. -.. code-block:: scala - - trait HasPeripheryPWMModuleImp extends LazyModuleImp { - implicit val p: Parameters - val outer: HasPeripheryPWM - - val pwmout = IO(Output(Bool())) - - pwmout := outer.pwm.module.io.pwmout - } +.. 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``. -.. code-block:: scala - - class TopWithPWM(implicit p: Parameters) extends Top - with HasPeripheryPWM { - override lazy val module = Module(new TopWithPWMModule(this)) - } - - class TopWithPWMModule(l: TopWithPWM) extends TopModule(l) - with HasPeripheryPWMModuleImp - +.. 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. @@ -174,52 +126,24 @@ The ``Top`` classes already have the basic peripherals included for us, so we wi 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 ``TopWithPWM`` instead of the default ``Top``. +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``. -.. code-block:: scala +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: WithPWMTop + :end-before: DOC include end: WithPWMTop - class WithPWMTop extends Config((site, here, up) => { - case BuildTop => (p: Parameters) => - Module(LazyModule(new TopWithPWM()(p)).module) - }) +And finally, we create a configuration class in ``generators/example/src/main/scala/Configs.scala`` that uses this mixin. -And finally, we create a configuration class in ``generators/example/src/main/scala/RocketConfigs.scala`` that uses this mixin. - -.. code-block:: scala - - class PWMRocketConfig extends Config( - new WithPWMTop ++ - new WithBootROM ++ - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.system.BaseConfig) +.. 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``. -.. code-block:: c - - #define PWM_PERIOD 0x2000 - #define PWM_DUTY 0x2008 - #define PWM_ENABLE 0x2010 - - static inline void write_reg(unsigned long addr, unsigned long data) - { - volatile unsigned long *ptr = (volatile unsigned long *) addr; - *ptr = data; - } - - static inline unsigned long read_reg(unsigned long addr) - { - volatile unsigned long *ptr = (volatile unsigned long *) addr; - return *ptr; - } - - int main(void) - { - write_reg(PWM_PERIOD, 20); - write_reg(PWM_DUTY, 5); - write_reg(PWM_ENABLE, 1); - } - +.. 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. diff --git a/generators/example/src/main/scala/ConfigMixins.scala b/generators/example/src/main/scala/ConfigMixins.scala index 17cbcaa5..313129f2 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -70,10 +70,12 @@ class WithDTMTop extends Config((site, here, up) => { /** * 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 diff --git a/generators/example/src/main/scala/PWM.scala b/generators/example/src/main/scala/PWM.scala index 2cec926e..bd6056f4 100644 --- a/generators/example/src/main/scala/PWM.scala +++ b/generators/example/src/main/scala/PWM.scala @@ -10,6 +10,7 @@ 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 { @@ -64,19 +65,23 @@ trait PWMModule extends HasRegMap { 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 @@ -88,7 +93,9 @@ trait HasPeripheryPWMTL { this: BaseSubsystem => 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 @@ -97,6 +104,7 @@ trait HasPeripheryPWMTLModuleImp extends LazyModuleImp { pwmout := outer.pwm.module.io.pwmout } +// DOC include end: HasPeripheryPWMTLModuleImp trait HasPeripheryPWMAXI4 { this: BaseSubsystem => implicit val p: Parameters diff --git a/generators/example/src/main/scala/RocketConfigs.scala b/generators/example/src/main/scala/RocketConfigs.scala index 21a7d13a..a44fb4d5 100644 --- a/generators/example/src/main/scala/RocketConfigs.scala +++ b/generators/example/src/main/scala/RocketConfigs.scala @@ -39,12 +39,14 @@ class jtagRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) +// DOC include start: PWMRocketConfig class PWMRocketConfig extends Config( new WithPWMTop ++ // use top with tilelink-controlled PWM new WithBootROM ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) +// DOC include end: PWMRocketConfig class PWMRAXI4ocketConfig extends Config( new WithPWMAXI4Top ++ // use top with axi4-controlled PWM diff --git a/generators/example/src/main/scala/Top.scala b/generators/example/src/main/scala/Top.scala index 19990817..4d39a7dd 100644 --- a/generators/example/src/main/scala/Top.scala +++ b/generators/example/src/main/scala/Top.scala @@ -30,6 +30,7 @@ class TopModule[+L <: Top](l: L) extends SystemModule(l) with DontTouch //--------------------------------------------------------------------------------------------------------- +// DOC include start: TopWithPWMTL class TopWithPWMTL(implicit p: Parameters) extends Top with HasPeripheryPWMTL { @@ -39,6 +40,7 @@ class TopWithPWMTL(implicit p: Parameters) extends Top class TopWithPWMTLModule(l: TopWithPWMTL) extends TopModule(l) with HasPeripheryPWMTLModuleImp +// DOC include end: TopWithPWMTL //--------------------------------------------------------------------------------------------------------- class TopWithPWMAXI4(implicit p: Parameters) extends Top From cf5d64f8c87d7f0716e546685af94a189400b6b5 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 10 Sep 2019 10:07:19 -0700 Subject: [PATCH 69/91] fix Diplomacy Connectors symbols --- .../Diplomacy-Connectors.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst b/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst index 9fc837fd..f066dcf6 100644 --- a/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst +++ b/docs/TileLink-Diplomacy-Reference/Diplomacy-Connectors.rst @@ -14,24 +14,24 @@ Diplomacy nodes, not Chisel bundles. The basic connection operator always creates a single edge between the two nodes. -:=* ---- +:=\* +---- This is a "query" type connection operator. It can create multiple edges between nodes, with the number of edges determined by the client node (the node on the right side of the operator). This can be useful if you are connecting a multi-edge client to a nexus node or adapter node. -:*= ---- +:\*= +---- This is a "star" type connection operator. It also creates multiple edges, but the number of edges is determined by the manager (left side of operator), rather than the client. It's useful for connecting nexus nodes to multi-edge manager nodes. -:*=* ----- +:\*=\* +------ This is a "flex" connection operator. It creates multiple edges based on whichever side of the operator has a known number of edges. This can be used From 714d79e87d67da00453554f43c16abb1dd17d4aa Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 10 Sep 2019 10:09:11 -0700 Subject: [PATCH 70/91] fix a AXI4UserYanker reference --- docs/TileLink-Diplomacy-Reference/Widgets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TileLink-Diplomacy-Reference/Widgets.rst b/docs/TileLink-Diplomacy-Reference/Widgets.rst index a5a171d4..41fc033b 100644 --- a/docs/TileLink-Diplomacy-Reference/Widgets.rst +++ b/docs/TileLink-Diplomacy-Reference/Widgets.rst @@ -382,7 +382,7 @@ also uses the AXI4 user field to store some information, so you will need an fields. Before you connect an AXI4 port to the AXI4ToTL widget, you will need to -add an :ref:`AXI4Fragmenter` and :ref:`UserYanker` because the converter cannot +add an :ref:`AXI4Fragmenter` and :ref:`AXI4UserYanker` because the converter cannot deal with multi-beat transactions or user fields. TLROM From 9bb4215c7d45dde978d152d7e4fb8259022fb38b Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 10 Sep 2019 10:55:50 -0700 Subject: [PATCH 71/91] add changes Alon requested --- docs/Customization/Memory-Hierarchy.rst | 10 +++++++++- docs/Generators/RocketChip.rst | 14 ++++++++++---- docs/TileLink-Diplomacy-Reference/index.rst | 5 +++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/docs/Customization/Memory-Hierarchy.rst b/docs/Customization/Memory-Hierarchy.rst index 2b9ff06b..967ae15b 100644 --- a/docs/Customization/Memory-Hierarchy.rst +++ b/docs/Customization/Memory-Hierarchy.rst @@ -58,7 +58,7 @@ and the number of banks must be powers of 2. new RocketConfig) The Broadcast Hub ----------------- +----------------- If you do not want to use the L2 cache (say, for a resource-limited embedded design), you can create a configuration without it. Instead of using the L2 @@ -102,3 +102,11 @@ number of DRAM channels is restricted to powers of two. class DualChannelRocketConfig extends Config( new WithNMemoryChannels(2) ++ new RocketConfig) + +In VCS and Verilator simulation, the DRAM is simulated using the +``SimAXIMem`` module, which simply attaches a single-cycle SRAM to each +memory channel. + +If you want a more realistic memory simulation, you can use FireSim, which +can simulate the timing of DDR3 controllers. More documentation on FireSim +memory models is available in the `FireSim docs `_. diff --git a/docs/Generators/RocketChip.rst b/docs/Generators/RocketChip.rst index 60b1e1cd..d18201b6 100644 --- a/docs/Generators/RocketChip.rst +++ b/docs/Generators/RocketChip.rst @@ -1,8 +1,13 @@ RocketChip ========== -RocketChip is an SoC generator supported by SiFive. Chipyard uses RocketChip -as the basis for producing a RISC-V SoC including Rocket, BOOM, and/or Hwacha. +RocketChip is an SoC generator developed at Berkeley and now supported by +SiFive. Chipyard uses RocketChip as the basis for producing a RISC-V SoC. + +RocketChip is distinct from Rocket, the in-order RISC-V CPU generator. +RocketChip includes many parts of the SoC besides the CPU. Though RocketChip +uses Rocket CPUs by default, it can also be configured to use the BOOM +out-of-order core generator or some other custom CPU generator instead. A detailed diagram of a typical RocketChip system is shown below. @@ -11,8 +16,9 @@ A detailed diagram of a typical RocketChip system is shown below. Tiles ----- -This is a dual-core ``Rocket`` system. Each ``Rocket`` core is grouped with a -page-table walker, L1 instruction cache, and L1 data cache into a ``RocketTile``. +The diagram shows a dual-core ``Rocket`` system. Each ``Rocket`` core is +grouped with a page-table walker, L1 instruction cache, and L1 data cache into +a ``RocketTile``. The ``Rocket`` core can also be swapped for a ``BOOM`` core. Each tile can also be configured with a RoCC accelerator that connects to the core as a diff --git a/docs/TileLink-Diplomacy-Reference/index.rst b/docs/TileLink-Diplomacy-Reference/index.rst index af00323b..23a5a175 100644 --- a/docs/TileLink-Diplomacy-Reference/index.rst +++ b/docs/TileLink-Diplomacy-Reference/index.rst @@ -7,7 +7,8 @@ peripherals, and DMA devices communicate with each other. RocketChip's TileLink implementation is built on top of Diplomacy, a framework for exchanging configuration information among Chisel generators in a two-phase -elaboration scheme. +elaboration scheme. For a detailed explanation of Diplomacy, see `the paper +by Cook, Terpstra, and Lee `_. A brief overview of how to connect simple TileLink widgets can be found in the :ref:`Adding-an-Accelerator` section. This section will provide a @@ -15,7 +16,7 @@ detailed reference for the TileLink and Diplomacy functionality provided by RocketChip. A detailed specification of the TileLink 1.7 protocol can be found on the -`SiFive website `. +`SiFive website `_. .. toctree:: From 200fec07e67f00b234f0df17fc3828caf386092d Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 10 Sep 2019 11:09:44 -0700 Subject: [PATCH 72/91] make purpose of CachelessRocketConfig clearer --- docs/Customization/Memory-Hierarchy.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Customization/Memory-Hierarchy.rst b/docs/Customization/Memory-Hierarchy.rst index 967ae15b..4295ab15 100644 --- a/docs/Customization/Memory-Hierarchy.rst +++ b/docs/Customization/Memory-Hierarchy.rst @@ -63,6 +63,9 @@ The Broadcast Hub If you do not want to use the L2 cache (say, for a resource-limited embedded design), you can create a configuration without it. Instead of using the L2 cache, you will instead use RocketChip's TileLink broadcast hub. +To make such a configuration, you can just copy the definition of +``RocketConfig`` but omit the ``WithInclusiveCache`` mixin from the +list of included mixims. .. code-block:: scala From c6f6b2e11776cad07a9831c7db59337d7f38b652 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Tue, 10 Sep 2019 11:10:00 -0700 Subject: [PATCH 73/91] mention address of BootROM and first instruction --- docs/Customization/Boot-Process.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Customization/Boot-Process.rst b/docs/Customization/Boot-Process.rst index df7e6931..0557b8bb 100644 --- a/docs/Customization/Boot-Process.rst +++ b/docs/Customization/Boot-Process.rst @@ -10,6 +10,9 @@ BootROM and RISC-V Frontend Server The first instructions to run when the SoC is powered on are those stored in the BootROM. The assembly for the BootROM code is located in `generators/testchipip/src/main/resources/testchipip/bootrom/bootrom.S `_. +The BootROM address space starts at ``0x10000`` and execution starts at address +``0x10040``, which is marked by the ``_hang`` label in the BootROM assembly. + 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 From 069bb5544274e0d4998cf19a98b39c7e1cd87bd4 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 14:26:51 -0700 Subject: [PATCH 74/91] a bit more explanation of site, here, up --- docs/Chipyard-Basics/Configs-Parameters-Mixins.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst b/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst index d9becfdf..09b86e39 100644 --- a/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst +++ b/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst @@ -65,6 +65,11 @@ Thus, the order of the parameters being set will first start with the ``DefaultE new DefaultExampleConfig ) +The ``site``, ``here``, and ``up`` objects in ``WithMyMoreComplexAcceleratorConfig`` are maps from configuration keys to their definitions. +The ``site`` map gives you the definitions as seen from the root of the configuration hierarchy (in this example, ``SomeAdditiveConfig``). +The ``here`` map gives the definitions as seen at the current level of the hierarchy (i.e. in ``WithMyMoreComplexAcceleratorConfig`` itself). +The ``up`` map gives the definitions as seen from the next level up from the current (i.e. from ``WithMyAcceleratorParams``). + Cake Pattern ------------------------- From bc903b840723af4597b71c45d48ca0d9d95fcb3d Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 14:34:57 -0700 Subject: [PATCH 75/91] more on customization of L1 --- docs/Customization/Memory-Hierarchy.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/Customization/Memory-Hierarchy.rst b/docs/Customization/Memory-Hierarchy.rst index 4295ab15..7864ddcc 100644 --- a/docs/Customization/Memory-Hierarchy.rst +++ b/docs/Customization/Memory-Hierarchy.rst @@ -22,6 +22,20 @@ configure 4 KiB direct-mapped caches for L1I and L1D. new WithNMediumCores(1) ++ new RocketConfig) +If you only want to change the size or associativity, there are configuration +mixins for those too. + +.. code-block:: scala + + 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) + 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. From 173743be6d6ff3583c8dc54da0b3e5d47ba6e82e Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Wed, 11 Sep 2019 18:29:38 -0700 Subject: [PATCH 76/91] [sbt] Remove the firrtl subproject --- build.sbt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/build.sbt b/build.sbt index 1ab82f27..09b81f97 100644 --- a/build.sbt +++ b/build.sbt @@ -69,21 +69,16 @@ def isolateAllTests(tests: Seq[TestDefinition]) = tests map { test => // Subproject definitions begin // // NB: FIRRTL should not be a managed dependency of chisel or rocketchip. -// Instead, they will get firrtl from the JAR file placed in /lib +// Instead, they will get firrtl from the JAR file placed in lib/ lazy val chisel = (project in rocketChipDir / "chisel3") -lazy val firrtl = (project in file("tools/firrtl")) - .settings(commonSettings) - lazy val firrtl_interpreter = (project in file("tools/firrtl-interpreter")) - .dependsOn(firrtl) .settings(commonSettings) -lazy val treadle = freshProject("treadle", file("tools/treadle")) - .dependsOn(firrtl) +lazy val treadle = (project in file("tools/treadle")) .settings(commonSettings) -lazy val `chisel-testers` = freshProject("chisel-testers", file("./tools/chisel-testers")) +lazy val `chisel-testers` = freshProject("chisel-testers", file("tools/chisel-testers")) .dependsOn(treadle, firrtl_interpreter, chisel) .settings( commonSettings, From 19a61b3c1a8cf911805313b331ae735c2924c6fe Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 16:12:35 -0700 Subject: [PATCH 77/91] document return values of edge methods --- .../EdgeFunctions.rst | 106 +++++++++++++++++- 1 file changed, 100 insertions(+), 6 deletions(-) diff --git a/docs/TileLink-Diplomacy-Reference/EdgeFunctions.rst b/docs/TileLink-Diplomacy-Reference/EdgeFunctions.rst index 984525ce..6385f908 100644 --- a/docs/TileLink-Diplomacy-Reference/EdgeFunctions.rst +++ b/docs/TileLink-Diplomacy-Reference/EdgeFunctions.rst @@ -18,6 +18,12 @@ from memory. The D channel response to this message will be an - ``toAddress: UInt`` - The address to read from - ``lgSize: UInt`` - Base two logarithm of the number of bytes to be read +**Returns:** + +A ``(Bool, TLBundleA)`` tuple. The first item in the pair is a boolean +indicating whether or not the operation is legal for this edge. The second +is the A channel bundle. + Put --- @@ -37,6 +43,12 @@ including the address. The manager will respond to this message with a single - ``data: UInt`` - The data to write on this beat. - ``mask: UInt`` - (optional) The write mask for this beat. +**Returns:** + +A ``(Bool, TLBundleA)`` tuple. The first item in the pair is a boolean +indicating whether or not the operation is legal for this edge. The second +is the A channel bundle. + Arithmetic ---------- @@ -56,6 +68,12 @@ of an ``AccessAckData``. - ``data: UInt`` - Right-hand operand of the arithmetic operation - ``atomic: UInt`` - Arithmetic operation type (from ``TLAtomics``) +**Returns:** + +A ``(Bool, TLBundleA)`` tuple. The first item in the pair is a boolean +indicating whether or not the operation is legal for this edge. The second +is the A channel bundle. + Logical ------- @@ -73,6 +91,12 @@ memory location will be returned in an ``AccessAckData`` response. - ``data: UInt`` - Right-hand operand of the logical operation - ``atomic: UInt`` - Logical operation type (from ``TLAtomics``) +**Returns:** + +A ``(Bool, TLBundleA)`` tuple. The first item in the pair is a boolean +indicating whether or not the operation is legal for this edge. The second +is the A channel bundle. + Hint ---- @@ -93,6 +117,12 @@ sent in response. - ``lgSize: UInt`` - Base two logarithm of the number of bytes to prefetch - ``param: UInt`` - Hint type (from TLHints) +**Returns:** + +A ``(Bool, TLBundleA)`` tuple. The first item in the pair is a boolean +indicating whether or not the operation is legal for this edge. The second +is the A channel bundle. + AccessAck --------- @@ -105,6 +135,10 @@ message. If the optional ``data`` field is supplied, it will be an - ``a: TLBundleA`` - The A channel message to acknowledge - ``data: UInt`` - (optional) The data to send back +**Returns:** + +The ``TLBundleD`` for the D channel message. + HintAck ------- @@ -114,18 +148,66 @@ Constructor for a TLBundleD encoding a ``HintAck`` message. - ``a: TLBundleA`` - The A channel message to acknowledge -first/last/count ----------------- +**Returns:** -These methods take a decoupled channel (either the A channel or D channel) -and determines whether the current beat is the first of the transaction, -whether the current beat is the last in the transaction, or the count -(starting from 0) of the current beat in the transaction. +The ``TLBundleD`` for the D channel message. + +first +----- + +This method take a decoupled channel (either the A channel or D channel) +and determines whether the current beat is the first beat in the transaction. **Arguments:** - ``x: DecoupledIO[TLChannel]`` - The decoupled channel to snoop on. +**Returns:** + +A ``Boolean`` which is true if the current beat is the first, or false otherwise. + +last +---- + +This method take a decoupled channel (either the A channel or D channel) +and determines whether the current beat is the last in the transaction. + +**Arguments:** + + - ``x: DecoupledIO[TLChannel]`` - The decoupled channel to snoop on. + +**Returns:** + +A ``Boolean`` which is true if the current beat is the last, or false otherwise. + +done +---- + +Equivalent to ``x.fire() && last(x)``. + +**Arguments:** + + - ``x: DecoupledIO[TLChannel]`` - The decoupled channel to snoop on. + +**Returns:** + +A ``Boolean`` which is true if the current beat is the last and a beat is +sent on this cycle. False otherwise. + +count +----- + +This method take a decoupled channel (either the A channel or D channel) and +determines the count (starting from 0) of the current beat in the transaction. + +**Arguments:** + + - ``x: DecoupledIO[TLChannel]`` - The decoupled channel to snoop on. + +**Returns:** + +A ``UInt`` indicating the count of the current beat. + numBeats --------- @@ -136,6 +218,10 @@ for the transaction. - ``x: TLChannel`` - The TileLink bundle to get the number of beats from +**Returns:** + +A ``UInt`` that is the number of beats in the current transaction. + numBeats1 --------- @@ -147,6 +233,10 @@ this is more efficient. - ``x: TLChannel`` - The TileLink bundle to get the number of beats from +**Returns:** + +A ``UInt`` that is the number of beats in the current transaction minus one. + hasData -------- @@ -156,3 +246,7 @@ if the message is a PutFull, PutPartial, Arithmetic, Logical, or AccessAckData. **Arguments:** - ``x: TLChannel`` - The TileLink bundle to check + +**Returns:** + +A ``Boolean`` that is true if the current message has data and false otherwise. From a71153a94d30d4d388d92e11dd7c47d2c1cca913 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 16:57:11 -0700 Subject: [PATCH 78/91] fix some reference in Chipyard Components --- docs/Chipyard-Basics/Chipyard-Components.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Chipyard-Basics/Chipyard-Components.rst b/docs/Chipyard-Basics/Chipyard-Components.rst index 49aff86a..250beb85 100644 --- a/docs/Chipyard-Basics/Chipyard-Components.rst +++ b/docs/Chipyard-Basics/Chipyard-Components.rst @@ -86,12 +86,12 @@ Sims **verilator (Verilator wrapper)** Verilator is an open source Verilog simulator. The ``verilator`` directory provides wrappers which construct Verilator-based simulators from relevant generated RTL, allowing for execution of test RISC-V programs on the simulator (including vcd waveform files). - See :ref:`Verilator` for more information. + See :ref:`Verilator (Open-Source)` for more information. **vcs (VCS wrapper)** VCS is a proprietary Verilog simulator. Assuming the user has valid VCS licenses and installations, the ``vcs`` directory provides wrappers which construct VCS-based simulators from relevant generated RTL, allowing for execution of test RISC-V programs on the simulator (including vcd/vpd waveform files). - See :ref:`VCS` for more information. + See :ref:`Synopsys VCS (License Required)` for more information. **FireSim** FireSim is an open-source FPGA-accelerated simulation platform, using Amazon Web Services (AWS) EC2 F1 instances on the public cloud. @@ -109,4 +109,4 @@ VLSI The HAMMER flow provide automated scripts which generate relevant tool commands based on a higher level description of physical design constraints. The HAMMER flow also allows for re-use of process technology knowledge by enabling the construction of process-technology-specific plug-ins, which describe particular constraints relating to that process technology (obsolete standard cells, metal layer routing constraints, etc.). The HAMMER flow requires access to proprietary EDA tools and process technology libraries. - See :ref:`HAMMER` for more information. + See :ref:`Core HAMMER` for more information. From f31f629505ba632408a88018e90f3b19c98e5f7b Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 17:05:47 -0700 Subject: [PATCH 79/91] replace broken :numref: --- docs/Chipyard-Basics/Configs-Parameters-Mixins.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst b/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst index 09b86e39..1d0aa813 100644 --- a/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst +++ b/docs/Chipyard-Basics/Configs-Parameters-Mixins.rst @@ -21,7 +21,7 @@ Configs are additive, can override each other, and can be composed of other Conf The naming convention for an additive Config is ``With``, while the naming convention for a non-additive Config will be ````. Configs can take arguments which will in-turn set parameters in the design or reference other parameters in the design (see :ref:`Parameters`). -:numref:`basic-config-example` shows a basic additive Config class that takes in zero arguments and instead uses hardcoded values to set the RTL design parameters. +This example shows a basic additive Config class that takes in zero arguments and instead uses hardcoded values to set the RTL design parameters. In this example, ``MyAcceleratorConfig`` is a Scala case class that defines a set of variables that the generator can use when referencing the ``MyAcceleratorKey`` in the design. .. _basic-config-example: @@ -38,7 +38,7 @@ In this example, ``MyAcceleratorConfig`` is a Scala case class that defines a se someLength = 256) }) -This next example (:numref:`complex-config-example`) shows a "higher-level" additive Config that uses prior parameters that were set to derive other parameters. +This next example shows a "higher-level" additive Config that uses prior parameters that were set to derive other parameters. .. _complex-config-example: .. code-block:: scala @@ -52,7 +52,7 @@ This next example (:numref:`complex-config-example`) shows a "higher-level" addi hartId = up(RocketTilesKey, site).length) }) -:numref:`top-level-config` shows a non-additive Config that combines the prior two additive Configs using ``++``. +The following example shows a non-additive Config that combines the prior two additive Configs using ``++``. The additive Configs are applied from the right to left in the list (or bottom to top in the example). Thus, the order of the parameters being set will first start with the ``DefaultExampleConfig``, then ``WithMyAcceleratorParams``, then ``WithMyMoreComplexAcceleratorConfig``. @@ -76,7 +76,7 @@ Cake Pattern A cake pattern is a Scala programming pattern, which enable "mixing" of multiple traits or interface definitions (sometimes referred to as dependency injection). It is used in the Rocket Chip SoC library and Chipyard framework in merging multiple system components and IO interfaces into a large system component. -:numref:`cake-example` shows a Rocket Chip based SoC that merges multiple system components (BootROM, UART, etc) into a single top-level design. +This example shows a Rocket Chip based SoC that merges multiple system components (BootROM, UART, etc) into a single top-level design. .. _cake-example: .. code-block:: scala @@ -97,7 +97,7 @@ Mix-in A mix-in is a Scala trait, which sets parameters for specific system components, as well as enabling instantiation and wiring of the relevant system components to system buses. The naming convention for an additive mix-in is ``Has``. -This is show in :numref:`cake-example` where things such as ``HasPeripherySerial`` connect a RTL component to a bus and expose signals to the top-level. +This is shown in the MySoC class where things such as ``HasPeripherySerial`` connect a RTL component to a bus and expose signals to the top-level. Additional References --------------------------- From 2d717bfcae0695ffbd982793e37ef241b6248b1a Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 17:35:18 -0700 Subject: [PATCH 80/91] add documentation code snippets to example project --- .../example/src/main/scala/ConfigMixins.scala | 11 ++ .../example/src/main/scala/InitZero.scala | 69 +++++++ .../src/main/scala/RegisterNodeExample.scala | 177 ++++++++++++++++++ .../src/main/scala/RocketConfigs.scala | 10 + generators/example/src/main/scala/Top.scala | 11 ++ 5 files changed, 278 insertions(+) create mode 100644 generators/example/src/main/scala/InitZero.scala create mode 100644 generators/example/src/main/scala/RegisterNodeExample.scala diff --git a/generators/example/src/main/scala/ConfigMixins.scala b/generators/example/src/main/scala/ConfigMixins.scala index 313129f2..a829db22 100644 --- a/generators/example/src/main/scala/ConfigMixins.scala +++ b/generators/example/src/main/scala/ConfigMixins.scala @@ -159,3 +159,14 @@ 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 diff --git a/generators/example/src/main/scala/InitZero.scala b/generators/example/src/main/scala/InitZero.scala new file mode 100644 index 00000000..3a90bfcc --- /dev/null +++ b/generators/example/src/main/scala/InitZero.scala @@ -0,0 +1,69 @@ +package example + +import chisel3._ +import chisel3.util._ +import freechips.rocketchip.subsystem.{BaseSubsystem, CacheBlockBytes} +import freechips.rocketchip.config.{Parameters, Field} +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, IdRange} +import testchipip.TLHelper + +case class InitZeroConfig(base: BigInt, size: BigInt) +case object InitZeroKey extends Field[InitZeroConfig] + +class InitZero(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeClientNode( + name = "init-zero", sourceId = IdRange(0, 1)) + + lazy val module = new InitZeroModuleImp(this) +} + +class InitZeroModuleImp(outer: InitZero) extends LazyModuleImp(outer) { + val config = p(InitZeroKey) + + val (mem, edge) = outer.node.out(0) + val addrBits = edge.bundle.addressBits + val blockBytes = p(CacheBlockBytes) + + require(config.size % blockBytes == 0) + + val s_init :: s_write :: s_resp :: s_done :: Nil = Enum(4) + val state = RegInit(s_init) + + val addr = Reg(UInt(addrBits.W)) + val bytesLeft = Reg(UInt(log2Ceil(config.size+1).W)) + + mem.a.valid := state === s_write + mem.a.bits := edge.Put( + fromSource = 0.U, + toAddress = addr, + lgSize = log2Ceil(blockBytes).U, + data = 0.U)._2 + mem.d.ready := state === s_resp + + when (state === s_init) { + addr := config.base.U + bytesLeft := config.size.U + state := s_write + } + + when (edge.done(mem.a)) { + addr := addr + blockBytes.U + bytesLeft := bytesLeft - blockBytes.U + state := s_resp + } + + when (mem.d.fire()) { + state := Mux(bytesLeft === 0.U, s_done, s_write) + } +} + +trait HasPeripheryInitZero { 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 +} diff --git a/generators/example/src/main/scala/RegisterNodeExample.scala b/generators/example/src/main/scala/RegisterNodeExample.scala new file mode 100644 index 00000000..a4e2cb02 --- /dev/null +++ b/generators/example/src/main/scala/RegisterNodeExample.scala @@ -0,0 +1,177 @@ +// DOC include start: MyDeviceController + +import chisel3._ +import chisel3.util._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink.TLRegisterNode + +class MyDeviceController(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice("my-device", Seq("tutorial,my-device0")) + val node = TLRegisterNode( + address = Seq(AddressSet(0x10028000, 0xfff)), + device = device, + beatBytes = 8, + concurrency = 1) + + lazy val module = new LazyModuleImp(this) { + val bigReg = RegInit(0.U(64.W)) + val mediumReg = RegInit(0.U(32.W)) + val smallReg = RegInit(0.U(16.W)) + + val tinyReg0 = RegInit(0.U(4.W)) + val tinyReg1 = RegInit(0.U(4.W)) + + node.regmap( + 0x00 -> Seq(RegField(64, bigReg)), + 0x08 -> Seq(RegField(32, mediumReg)), + 0x0C -> Seq(RegField(16, smallReg)), + 0x0E -> Seq( + RegField(4, tinyReg0), + RegField(4, tinyReg1))) + } +} + +// DOC include end: MyDeviceController + +// DOC include start: MyAXI4DeviceController +import freechips.rocketchip.amba.axi4.AXI4RegisterNode + +class MyAXI4DeviceController(implicit p: Parameters) extends LazyModule { + val node = AXI4RegisterNode( + address = AddressSet(0x10029000, 0xfff), + beatBytes = 8, + concurrency = 1) + + lazy val module = new LazyModuleImp(this) { + val bigReg = RegInit(0.U(64.W)) + val mediumReg = RegInit(0.U(32.W)) + val smallReg = RegInit(0.U(16.W)) + + val tinyReg0 = RegInit(0.U(4.W)) + val tinyReg1 = RegInit(0.U(4.W)) + + node.regmap( + 0x00 -> Seq(RegField(64, bigReg)), + 0x08 -> Seq(RegField(32, mediumReg)), + 0x0C -> Seq(RegField(16, smallReg)), + 0x0E -> Seq( + RegField(4, tinyReg0), + RegField(4, tinyReg1))) + } +} +// DOC include end: MyAXI4DeviceController + +class MyQueueRegisters(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice("my-queue", Seq("tutorial,my-queue0")) + val node = TLRegisterNode( + address = Seq(AddressSet(0x1002A000, 0xfff)), + device = device, + beatBytes = 8, + concurrency = 1) + + lazy val module = new LazyModuleImp(this) { +// DOC include start: MyQueueRegisters + // 4-entry 64-bit queue + val queue = Module(new Queue(UInt(64.W), 4)) + + node.regmap( + 0x00 -> Seq(RegField(64, queue.io.deq, queue.io.enq))) +// DOC include end: MyQueueRegisters + } +} + +class MySeparateQueueRegisters(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice("my-queue", Seq("tutorial,my-queue1")) + val node = TLRegisterNode( + address = Seq(AddressSet(0x1002B000, 0xfff)), + device = device, + beatBytes = 8, + concurrency = 1) + + lazy val module = new LazyModuleImp(this) { + val queue = Module(new Queue(UInt(64.W), 4)) + +// DOC include start: MySeparateQueueRegisters + node.regmap( + 0x00 -> Seq(RegField.r(64, queue.io.deq)), + 0x08 -> Seq(RegField.w(64, queue.io.enq))) +// DOC include end: MySeparateQueueRegisters + } +} + +class MyCounterRegisters(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice("my-counters", Seq("tutorial,my-counters0")) + val node = TLRegisterNode( + address = Seq(AddressSet(0x1002C000, 0xfff)), + device = device, + beatBytes = 8, + concurrency = 1) + + lazy val module = new LazyModuleImp(this) { +// DOC include start: MyCounterRegisters + val counter = RegInit(0.U(64.W)) + + def readCounter(ready: Bool): (Bool, UInt) = { + when (ready) { counter := counter - 1.U } + (true.B, counter) + } + + def writeCounter(valid: Bool, bits: UInt): Bool = { + when (valid) { counter := counter + 1.U } + // Ignore bits + true.B + } + + node.regmap( + 0x00 -> Seq(RegField.r(64, readCounter(_))), + 0x08 -> Seq(RegField.w(64, writeCounter(_, _)))) +// DOC include end: MyCounterRegisters + } +} + +class MyCounterReqRespRegisters(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice("my-counters", Seq("tutorial,my-counters1")) + val node = TLRegisterNode( + address = Seq(AddressSet(0x1002D000, 0xfff)), + device = device, + beatBytes = 8, + concurrency = 1) + + lazy val module = new LazyModuleImp(this) { +// DOC include start: MyCounterReqRespRegisters + val counter = RegInit(0.U(64.W)) + + def readCounter(ivalid: Bool, oready: Bool): (Bool, Bool, UInt) = { + val responding = RegInit(false.B) + + when (ivalid && !responding) { responding := true.B } + + when (responding && oready) { + counter := counter - 1.U + responding := false.B + } + + (!responding, responding, counter) + } + + def writeCounter(ivalid: Bool, oready: Bool, bits: UInt): (Bool, Bool) = { + val responding = RegInit(false.B) + + when (ivalid && !responding) { responding := true.B } + + when (responding && oready) { + counter := counter + 1.U + responding := false.B + } + + (!responding, responding) + } + + node.regmap( + 0x00 -> Seq(RegField.r(64, readCounter(_, _))), + 0x08 -> Seq(RegField.w(64, writeCounter(_, _, _)))) +// DOC include end: MyCounterReqRespRegisters + } +} diff --git a/generators/example/src/main/scala/RocketConfigs.scala b/generators/example/src/main/scala/RocketConfigs.scala index a44fb4d5..cd78b9d2 100644 --- a/generators/example/src/main/scala/RocketConfigs.scala +++ b/generators/example/src/main/scala/RocketConfigs.scala @@ -109,3 +109,13 @@ class Sha3RocketConfig extends Config( new freechips.rocketchip.subsystem.WithInclusiveCache ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig) + +// DOC include start: InitZeroRocketConfig +class InitZeroRocketConfig extends Config( + new WithInitZero(0x88000000L, 0x1000L) ++ + new WithInitZeroTop ++ + new WithBootROM ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.system.BaseConfig) +// DOC include end: InitZeroRocketConfig diff --git a/generators/example/src/main/scala/Top.scala b/generators/example/src/main/scala/Top.scala index 4d39a7dd..94bed0de 100644 --- a/generators/example/src/main/scala/Top.scala +++ b/generators/example/src/main/scala/Top.scala @@ -80,3 +80,14 @@ class TopWithDTM(implicit p: Parameters) extends System } 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 From 9a8d6c908f20484b6d147cc891e842d3a35ded16 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 17:54:08 -0700 Subject: [PATCH 81/91] fix verilator invocation in Adding an Accelerator --- docs/Customization/Adding-An-Accelerator.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Customization/Adding-An-Accelerator.rst b/docs/Customization/Adding-An-Accelerator.rst index 6a95fa84..b0e031a2 100644 --- a/docs/Customization/Adding-An-Accelerator.rst +++ b/docs/Customization/Adding-An-Accelerator.rst @@ -155,9 +155,9 @@ Now with all of that done, we can go ahead and run our simulation. .. code-block:: shell - cd verilator - make CONFIG=PWMConfig - ./simulator-example-PWMConfig ../tests/pwm.riscv + cd sims/verilator + make CONFIG=PWMRocketConfig TOP=TopWithPWMTL + ./simulator-example-PWMRocketConfig ../../tests/pwm.riscv Adding a RoCC Accelerator ---------------------------- From 6ae60b94c6da6587f00624043a84c6f3061187a1 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 17:56:12 -0700 Subject: [PATCH 82/91] correct capitalization in Adding an Accelerator/Device --- docs/Customization/Adding-An-Accelerator.rst | 2 +- docs/Generators/RocketChip.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Customization/Adding-An-Accelerator.rst b/docs/Customization/Adding-An-Accelerator.rst index b0e031a2..20aea8c0 100644 --- a/docs/Customization/Adding-An-Accelerator.rst +++ b/docs/Customization/Adding-An-Accelerator.rst @@ -1,6 +1,6 @@ .. _adding-an-accelerator: -Adding An Accelerator/Device +Adding an Accelerator/Device =============================== Accelerators or custom IO devices can be added to your SoC in several ways: diff --git a/docs/Generators/RocketChip.rst b/docs/Generators/RocketChip.rst index d18201b6..34d8f563 100644 --- a/docs/Generators/RocketChip.rst +++ b/docs/Generators/RocketChip.rst @@ -59,7 +59,7 @@ It can also optionally expose an external AXI4 port, which can be attached to vendor-supplied AXI4 IP. To learn more about adding MMIO peripherals, check out the :ref:`MMIO Peripheral` -section of :ref:`Adding An Accelerator/Device`. +section of :ref:`Adding an Accelerator/Device`. DMA --- From d5bccc04552b04f7de7f7062b2461b41d8de49b5 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 18:08:45 -0700 Subject: [PATCH 83/91] add additional example code as literalincludes --- docs/Customization/Adding-An-Accelerator.rst | 62 +++---- .../Register-Router.rst | 156 +++--------------- .../src/main/scala/RegisterNodeExample.scala | 6 +- 3 files changed, 54 insertions(+), 170 deletions(-) diff --git a/docs/Customization/Adding-An-Accelerator.rst b/docs/Customization/Adding-An-Accelerator.rst index 20aea8c0..3c0ea4eb 100644 --- a/docs/Customization/Adding-An-Accelerator.rst +++ b/docs/Customization/Adding-An-Accelerator.rst @@ -229,51 +229,33 @@ To add RoCC instructions in your program, use the RoCC C macros provided in ``te Adding a DMA port ------------------- -IO devices or accelerators (like a disk or network driver), we may want to have the device write directly to the coherent memory system instead. -To add a device like that, you would do the following. +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. -.. code-block:: scala +.. literalinclude:: ../../generators/example/src/main/scala/InitZero.scala + :language: scala - class DMADevice(implicit p: Parameters) extends LazyModule { - val node = TLHelper.makeClientNode( - name = "dma-device", sourceId = IdRange(0, 1)) +.. literalinclude:: ../../generators/example/src/main/scala/Top.scala + :language: scala + :start-after: DOC include start: TopWithInitZero + :end-before: DOC include end: TopWithInitZero - lazy val module = new DMADeviceModule(this) - } +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`. - class DMADeviceModule(outer: DMADevice) extends LazyModuleImp(outer) { - val io = IO(new Bundle { - val ext = new ExtBundle - }) +Once we've created our top-level module including the DMA widget, we can create a configuration for it as we did before. - val (mem, edge) = outer.node.out(0) +.. literalinclude:: ../../generators/example/src/main/scala/ConfigMixins.scala + :language: scala + :start-after: DOC include start: WithInitZero + :end-before: DOC include end: WithInitZero - // ... rest of the code ... - } - - trait HasPeripheryDMA { this: BaseSubsystem => - implicit val p: Parameters - - val dma = LazyModule(new DMADevice) - - fbus.fromPort(Some(portName))() := dma.node - } - - trait HasPeripheryDMAModuleImp extends LazyModuleImp { - val ext = IO(new ExtBundle) - ext <> outer.dma.module.io.ext - } - - class TopWithDMA(implicit p: Parameters) extends Top - with HasPeripheryDMA { - override lazy val module = new TopWithDMAModule - } - - class TopWithDMAModule(l: TopWithDMA) extends TopModule(l) - with HasPeripheryDMAModuleImp +.. literalinclude:: ../../generators/example/src/main/scala/RocketConfigs.scala + :language: scala + :start-after: DOC include start: InitZeroRocketConfig + :end-before: DOC include end: InitZeroRocketConfig -The ``ExtBundle`` contains the signals we connect off-chip that we get data from. -The DMADevice also has a Tilelink client port that we connect into the L1-L2 crossbar through the frontend bus (fbus). -The sourceId variable given in the ``TLClientNode`` instantiation determines the range of ids that can be used in acquire messages from this device. -Since we specified [0, 1) as our range, only the ID 0 can be used. diff --git a/docs/TileLink-Diplomacy-Reference/Register-Router.rst b/docs/TileLink-Diplomacy-Reference/Register-Router.rst index 4f129e47..cc735578 100644 --- a/docs/TileLink-Diplomacy-Reference/Register-Router.rst +++ b/docs/TileLink-Diplomacy-Reference/Register-Router.rst @@ -18,39 +18,10 @@ This section will focus on the second method. Basic Usage ----------- -.. code-block:: scala - - import chisel3._ - import chisel3.util._ - import freechips.rocketchip.config.Parameters - import freechips.rocketchip.diplomacy.{SimpleDevice, AddressSet} - import freechips.rocketchip.tilelink.TLRegisterNode - - class MyDeviceController(implicit p: Parameters) extends LazyModule { - val device = new SimpleDevice("my-device", Seq("tutorial,my-device0")) - val node = TLRegisterNode( - address = Seq(AddressSet(0x10019000, 0xfff)), - device = device, - beatBytes = 8, - concurrency = 1) - - lazy val module = new LazyModuleImp(this) { - val bigReg = RegInit(0.U(64.W)) - val mediumReg = RegInit(0.U(32.W)) - val smallReg = RegInit(0.U(16.W)) - - val tinyReg0 = RegInit(0.U(4.W)) - val tinyReg1 = RegInit(0.U(4.W)) - - node.regmap( - 0x00 -> Seq(RegField(64, bigReg)), - 0x08 -> Seq(RegField(32, mediumReg)), - 0x0C -> Seq(RegField(16, smallReg)), - 0x0E -> Seq( - RegField(4, tinyReg0), - RegField(4, tinyReg1))) - } - } +.. literalinclude:: ../../generators/example/src/main/scala/RegisterNodeExample.scala + :language: scala + :start-after: DOC include start: MyDeviceController + :end-before: DOC include end: MyDeviceController The code example above shows a simple lazy module that uses the ``TLRegisterNode`` to memory map hardware registers of different sizes. The constructor has @@ -85,13 +56,10 @@ register. The ``RegField`` interface also provides support for reading and writing ``DecoupledIO`` interfaces. For instance, you can implement a hardware FIFO like so. -.. code-block:: scala - - // 4-entry 64-bit queue - val queue = Module(new Queue(UInt(64.W), 4)) - - node.regmap( - 0x00 -> Seq(RegField(64, queue.io.deq, queue.io.enq))) +.. literalinclude:: ../../generators/example/src/main/scala/RegisterNodeExample.scala + :language: scala + :start-after: DOC include start: MyQueueRegisters + :end-before: DOC include end: MyQueueRegisters This variant of the ``RegField`` constructor takes three arguments instead of two. The first argument is still the bit width. The second is the decoupled @@ -103,11 +71,10 @@ You need not specify both read and write for a register. You can also create read-only or write-only registers. So for the previous example, if you wanted enqueue and dequeue to use different addresses, you could write the following. -.. code-block:: scala - - node.regmap( - 0x00 -> Seq(RegField.r(64, queue.io.deq)), - 0x08 -> Seq(RegField.w(64, queue.io.enq))) +.. literalinclude:: ../../generators/example/src/main/scala/RegisterNodeExample.scala + :language: scala + :start-after: DOC include start: MySeparateQueueRegisters + :end-before: DOC include end: MySeparateQueueRegisters The read-only register function can also be used to read signals that aren't registers. @@ -126,24 +93,10 @@ You can also create registers using functions. Say, for instance, that you want to create a counter that gets incremented on a write and decremented on a read. -.. code-block:: scala - - val counter = RegInit(0.U(64.W)) - - def readCounter(ready: Bool): (Bool, UInt) = { - when (ready) { counter := counter - 1.U } - (true.B, counter) - } - - def writeCounter(valid: Bool, bits: UInt): Bool = { - when (valid) { counter := counter + 1.U } - // Ignore bits - true.B - } - - node.regmap( - 0x00 -> Seq(RegField.r(64, readCounter(_))), - 0x08 -> Seq(RegField.w(64, writeCounter(_, _)))) +.. literalinclude:: ../../generators/example/src/main/scala/RegisterNodeExample.scala + :language: scala + :start-after: DOC include start: MyCounterRegisters + :end-before: DOC include end: MyCounterRegisters The functions here are essentially the same as a decoupled interface. The read function gets passed the ``ready`` signal and returns the @@ -154,39 +107,10 @@ You can also pass functions that decouple the read/write request and response. The request will appear as a decoupled input and the response as a decoupled output. So for instance, if we wanted to do this for the previous example. -.. code-block:: scala - - val counter = RegInit(0.U(64.W)) - - def readCounter(ivalid: Bool, oready: Bool): (Bool, Bool, UInt) = { - val responding = RegInit(false.B) - - when (ivalid && !responding) { responding := true.B } - - when (responding && oready) { - counter := counter - 1.U - responding := false.B - } - - (!responding, responding, counter) - } - - def writeCounter(ivalid: Bool, bits: UInt, oready: Bool): (Bool, Bool) = { - val responding = RegInit(false.B) - - when (ivalid && !responding) { responding := true.B } - - when (responding && oready) { - counter := counter + 1.U - responding := false.B - } - - (!responding, responding) - } - - node.regmap( - 0x00 -> Seq(RegField.r(64, readCounter(_, _))), - 0x08 -> Seq(RegField.w(64, writeCounter(_, _, _)))) +.. literalinclude:: ../../generators/example/src/main/scala/RegisterNodeExample.scala + :language: scala + :start-after: DOC include start: MyCounterReqRespRegisters + :end-before: DOC include end: MyCounterReqRespRegisters In each function, we set up a state variable ``responding``. The function is ready to take requests when this is false and is sending a response when @@ -207,37 +131,11 @@ change the protocol being used. For instance, in the first example in :ref:`Basic Usage`, you could simply change the ``TLRegisterNode`` to and ``AXI4RegisterNode``. -.. code-block:: scala +.. literalinclude:: ../../generators/example/src/main/scala/RegisterNodeExample.scala + :language: scala + :start-after: DOC include start: MyAXI4DeviceController + :end-before: DOC include end: MyAXI4DeviceController - import chisel3._ - import chisel3.util._ - import freechips.rocketchip.config.Parameters - import freechips.rocketchip.diplomacy.{SimpleDevice, AddressSet} - import freechips.rocketchip.amba.axi4.AXI4RegisterNode - - class MyAXI4DeviceController(implicit p: Parameters) extends LazyModule { - val node = AXI4RegisterNode( - address = Seq(AddressSet(0x10019000, 0xfff)), - beatBytes = 8, - concurrency = 1) - - lazy val module = new LazyModuleImp(this) { - val bigReg = RegInit(0.U(64.W)) - val mediumReg = RegInit(0.U(32.W)) - val smallReg = RegInit(0.U(16.W)) - - val tinyReg0 = RegInit(0.U(4.W)) - val tinyReg1 = RegInit(0.U(4.W)) - - node.regmap( - 0x00 -> Seq(RegField(64, bigReg)), - 0x08 -> Seq(RegField(32, mediumReg)), - 0x0C -> Seq(RegField(16, smallReg)), - 0x0E -> Seq( - RegField(4, tinyReg0), - RegField(4, tinyReg1))) - } - } - -Other than the fact that AXI4 nodes don't take a ``device`` argument, -everything else is unchanged. +Other than the fact that AXI4 nodes don't take a ``device`` argument, and can +only have a single AddressSet instead of multiple, everything else is +unchanged. diff --git a/generators/example/src/main/scala/RegisterNodeExample.scala b/generators/example/src/main/scala/RegisterNodeExample.scala index a4e2cb02..cda91ffe 100644 --- a/generators/example/src/main/scala/RegisterNodeExample.scala +++ b/generators/example/src/main/scala/RegisterNodeExample.scala @@ -115,12 +115,14 @@ class MyCounterRegisters(implicit p: Parameters) extends LazyModule { def readCounter(ready: Bool): (Bool, UInt) = { when (ready) { counter := counter - 1.U } + // (ready, bits) (true.B, counter) } def writeCounter(valid: Bool, bits: UInt): Bool = { when (valid) { counter := counter + 1.U } // Ignore bits + // Return ready true.B } @@ -153,10 +155,11 @@ class MyCounterReqRespRegisters(implicit p: Parameters) extends LazyModule { responding := false.B } + // (iready, ovalid, obits) (!responding, responding, counter) } - def writeCounter(ivalid: Bool, oready: Bool, bits: UInt): (Bool, Bool) = { + def writeCounter(ivalid: Bool, oready: Bool, ibits: UInt): (Bool, Bool) = { val responding = RegInit(false.B) when (ivalid && !responding) { responding := true.B } @@ -166,6 +169,7 @@ class MyCounterReqRespRegisters(implicit p: Parameters) extends LazyModule { responding := false.B } + // (iready, ovalid) (!responding, responding) } From e68536a85256214efeef113ea532f9fb23c647fd Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Thu, 12 Sep 2019 18:14:39 -0700 Subject: [PATCH 84/91] add Google Group to the index --- docs/index.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index eff043df..61acfae3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,6 +12,16 @@ New to Chipyard? Jump to the :ref:`Chipyard Basics` page for more info. .. include:: Quick-Start.rst +Getting Help +------------ + +If you have a question about Chipyard that isn't answered by the existing +documentation, feel free to ask for help on the +`Chipyard Google Group `_. + +Table of Contents +----------------- + .. toctree:: :maxdepth: 3 :numbered: From 16cc5652380929668703fa6d120143e648785d60 Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Thu, 12 Sep 2019 15:39:56 -0700 Subject: [PATCH 85/91] [sbt] Purge berkeley library dependencies from all subprojects --- build.sbt | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/build.sbt b/build.sbt index 09b81f97..513b8b07 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,9 @@ import Tests._ +// This gives us a nicer handle to the root project instead of using the +// implicit one +lazy val chipyardRoot = RootProject(file(".")) + lazy val commonSettings = Seq( organization := "edu.berkeley.cs", version := "1.0", @@ -15,7 +19,10 @@ lazy val commonSettings = Seq( libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value, libraryDependencies += "com.github.scopt" %% "scopt" % "3.7.0", libraryDependencies += "org.scala-lang.modules" % "scala-jline" % "2.12.1", + libraryDependencies += "com.typesafe.play" %% "play-json" % "2.6.10", addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full), + unmanagedBase := (chipyardRoot / unmanagedBase).value, + allDependencies := allDependencies.value.filterNot(_.organization == "edu.berkeley.cs"), resolvers ++= Seq( Resolver.sonatypeRepo("snapshots"), Resolver.sonatypeRepo("releases"), @@ -68,8 +75,10 @@ def isolateAllTests(tests: Seq[TestDefinition]) = tests map { test => // Subproject definitions begin // -// NB: FIRRTL should not be a managed dependency of chisel or rocketchip. -// Instead, they will get firrtl from the JAR file placed in lib/ +// FIRRTL is handled as an unmanaged dependency. Make will build the firrtl jar +// before launching sbt if any of the firrtl source files has been updated +// The jar is dropped in chipyard's lib/ directory, which is used as the unmanagedBase +// for all subprojects lazy val chisel = (project in rocketChipDir / "chisel3") lazy val firrtl_interpreter = (project in file("tools/firrtl-interpreter")) @@ -78,8 +87,8 @@ lazy val firrtl_interpreter = (project in file("tools/firrtl-interpreter")) lazy val treadle = (project in file("tools/treadle")) .settings(commonSettings) -lazy val `chisel-testers` = freshProject("chisel-testers", file("tools/chisel-testers")) - .dependsOn(treadle, firrtl_interpreter, chisel) +lazy val chisel_testers = (project in file("tools/chisel-testers")) + .dependsOn(chisel, firrtl_interpreter, treadle) .settings( commonSettings, libraryDependencies ++= Seq( @@ -90,7 +99,7 @@ lazy val `chisel-testers` = freshProject("chisel-testers", file("tools/chisel-te ) ) - // Contains annotations & firrtl passes you may wish to use in rocket-chip without +// Contains annotations & firrtl passes you may wish to use in rocket-chip without // introducing a circular dependency between RC and MIDAS lazy val midasTargetUtils = ProjectRef(firesimDir, "targetutils") @@ -134,11 +143,11 @@ lazy val boom = (project in file("generators/boom")) .settings(commonSettings) lazy val sha3 = (project in file("generators/sha3")) - .dependsOn(rocketchip, `chisel-testers`) + .dependsOn(rocketchip, chisel_testers) .settings(commonSettings) lazy val tapeout = conditionalDependsOn(project in file("./tools/barstools/tapeout/")) - .dependsOn(`chisel-testers`) + .dependsOn(chisel_testers) .settings(commonSettings) lazy val mdf = (project in file("./tools/barstools/mdf/scalalib/")) @@ -149,8 +158,8 @@ lazy val barstoolsMacros = (project in file("./tools/barstools/macros/")) .enablePlugins(sbtassembly.AssemblyPlugin) .settings(commonSettings) -lazy val dsptools = freshProject("dsptools", file("./tools/dsptools")) - .dependsOn(chisel, `chisel-testers`) +lazy val dsptools = (project in file("./tools/dsptools")) + .dependsOn(chisel, chisel_testers) .settings( commonSettings, libraryDependencies ++= Seq( From 95ae46f4f29029a82951e752407b3e23c90d29f3 Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Thu, 12 Sep 2019 15:45:45 -0700 Subject: [PATCH 86/91] [sbt] Use tools/chisel3 not rocketchip/chisel3 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 513b8b07..8083dc3d 100644 --- a/build.sbt +++ b/build.sbt @@ -79,7 +79,7 @@ def isolateAllTests(tests: Seq[TestDefinition]) = tests map { test => // before launching sbt if any of the firrtl source files has been updated // The jar is dropped in chipyard's lib/ directory, which is used as the unmanagedBase // for all subprojects -lazy val chisel = (project in rocketChipDir / "chisel3") +lazy val chisel = (project in file("tools/chisel3")) lazy val firrtl_interpreter = (project in file("tools/firrtl-interpreter")) .settings(commonSettings) From ce94ca7840d883f1be3775e714e49aa4a7d9bc0a Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Fri, 13 Sep 2019 01:52:23 -0700 Subject: [PATCH 87/91] Fix Makefile .vpd rules not generating .out --- sims/vcs/Makefile | 2 +- sims/verilator/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sims/vcs/Makefile b/sims/vcs/Makefile index d8974525..6a65d0a2 100644 --- a/sims/vcs/Makefile +++ b/sims/vcs/Makefile @@ -92,7 +92,7 @@ $(sim_debug) : $(sim_vsrcs) $(sim_common_files) ######################################################################################### .PRECIOUS: $(output_dir)/%.vpd %.vpd $(output_dir)/%.vpd: $(output_dir)/% $(sim_debug) - $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< + (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< 3>&1 1>&2 2>&3 | spike-dasm > $<.out) ######################################################################################### # general cleanup rule diff --git a/sims/verilator/Makefile b/sims/verilator/Makefile index ae27afdf..b3185ade 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 & - $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) -v$@.vcd $(PERMISSIVE_OFF) $< + (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) +max-cycles=$(timeout_cycles) $(SIM_FLAGS) $(VERBOSE_FLAGS) -v$@.vcd $(PERMISSIVE_OFF) $< 3>&1 1>&2 2>&3 | spike-dasm > $<.out) ######################################################################################### # general cleanup rule From f96a70fc61421c58913930dbcd42b83d87a05cf0 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 16 Sep 2019 10:21:10 -0700 Subject: [PATCH 88/91] fix another instance of broken references --- docs/Chipyard-Basics/Running-A-Simulation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Chipyard-Basics/Running-A-Simulation.rst b/docs/Chipyard-Basics/Running-A-Simulation.rst index 7b3f0cc1..76eb0acb 100644 --- a/docs/Chipyard-Basics/Running-A-Simulation.rst +++ b/docs/Chipyard-Basics/Running-A-Simulation.rst @@ -9,7 +9,7 @@ Software RTL Simulation ------------------------ The Chipyard framework provides wrappers for two common software RTL simulators: the open-source Verilator simulator and the proprietary VCS simulator. -For more information on either of these simulators, please refer to :ref:`Verilator` or :ref:`VCS`. +For more information on either of these simulators, please refer to :ref:`Verilator (Open-Source)` or :ref:`Synopsys VCS (License Required)`. The following instructions assume at least one of these simulators is installed. Verilator/VCS Flows From 6465d9c59194780ab2203263ead32f12db5f5f5f Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 16 Sep 2019 10:25:10 -0700 Subject: [PATCH 89/91] move NodeTypes code to scala source --- .../NodeTypes.rst | 126 ++++------------- .../example/src/main/scala/NodeTypes.scala | 128 ++++++++++++++++++ 2 files changed, 152 insertions(+), 102 deletions(-) create mode 100644 generators/example/src/main/scala/NodeTypes.scala diff --git a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst index 79d8da74..be3fb33d 100644 --- a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst +++ b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst @@ -17,26 +17,10 @@ The L1 caches and DMA devices in RocketChip/Chipyard have client nodes. You can add a TileLink client node to your LazyModule using the TLHelper object from testchipip like so: -.. code-block:: scala - - import freechips.rocketchip.config.Parameters - import freechips.rocketchip.diplomacy._ - import freechips.rocketchip.tilelink.{TLClientParameters} - import testchipip.TLHelper - - class MyClient(implicit p: Parameters) extends LazyModule { - val node = TLHelper.makeClientNode(TLClientParameters( - name = "my-client", - sourceId = IdRange(0, 4), - requestFifo = true, - visibility = Seq(AddressSet(0x10000, 0xffff)))) - - lazy val module = new LazyModuleImp(this) { - val (tl, edge) = node.out(0) - - // Rest of code here - } - } +.. literalinclude:: ../../generators/example/src/main/scala/NodeTypes.scala + :language: scala + :start-after: DOC include start: MyClient + :end-before: DOC include end: MyClient The ``name`` argument identifies the node in the Diplomacy graph. It is the only required argument for TLClientParameters. @@ -82,33 +66,10 @@ TileLink managers take requests from clients on the A channel and send responses back on the D channel. You can create a manager node using the TLHelper like so: -.. code-block:: scala - - import freechips.rocketchip.config.Parameters - import freechips.rocketchip.diplomacy._ - import freechips.rocketchip.tilelink.{TLManagerParameters} - import testchipip.TLHelper - - class MyManager(implicit p: Parameters) extends LazyModule { - val device = new SimpleDevice("my-device", Seq("tutorial,my-device0")) - val beatBytes = 8 - val node = TLHelper.makeManagerNode(beatBytes, TLManagerParameters( - address = Seq(AddressSet(0x20000, 0xfff)), - resources = device.reg, - regionType = RegionType.UNCACHED, - executable = true, - supportsArithemetic = TransferSizes(1, beatBytes), - supportsLogical = TransferSizes(1, beatBytes), - supportsGet = TransferSizes(1, beatBytes), - supportsPutFull = TransferSizes(1, beatBytes), - supportsPutPartial = TransferSizes(1, beatBytes), - supportsHint = TransferSizes(1, beatBytes), - fifoId = Some(0))) - - lazy val module = new LazyModuleImp(this) { - val (tl, edge) = node.in(0) - } - } +.. literalinclude:: ../../generators/example/src/main/scala/NodeTypes.scala + :language: scala + :start-after: DOC include start: MyManager + :end-before: DOC include end: MyManager The ``makeManagerNode`` method takes two arguments. The first is ``beatBytes``, which is the physical width of the TileLink interface in bytes. The second @@ -185,71 +146,32 @@ to the outputs unchanged. This node is mainly used to combine multiple nodes into a single node with multiple edges. For instance, say we have two client lazy modules, each with their own client node. -.. code-block:: scala - - class MyClient1(implicit p: Parameters) extends LazyModule { - val node = TLHelper.makeClientNode("my-client1", IdRange(0, 1)) - - // ... - } - - class MyClient2(implicit p: Parameters) extends LazyModule { - val node = TLHelper.makeClientNode("my-client2", IdRange(0, 1)) - - // ... - } +.. literalinclude:: ../../generators/example/src/main/scala/NodeTypes.scala + :language: scala + :start-after: DOC include start: MyClient1+MyClient2 + :end-before: DOC include end: MyClient1+MyClient2 Now we instantiate these two clients in another lazy module and expose their nodes as a single node. -.. code-block:: scala - - class MyClientGroup(implicit p: Parameters) extends LazyModule { - val client1 = LazyModule(new MyClient1) - val client2 = LazyModule(new MyClient2) - val node = TLIdentityNode() - - node := client1.node - node := client2.node - - // ... - } +.. literalinclude:: ../../generators/example/src/main/scala/NodeTypes.scala + :language: scala + :start-after: DOC include start: MyClientGroup + :end-before: DOC include end: MyClientGroup We can also do the same for managers. -.. code-block:: scala - - class MyManager1(beatBytes: Int)(implicit p: Parameters) extends LazyModule { - val node = TLHelper.makeManagerNode(beatBytes, TLManagerParameters( - address = Seq(AddressSet(0x0, 0xfff)))) - // ... - } - - class MyManager2(beatBytes: Int)(implicit p: Parameters) extends LazyModule { - val node = TLHelper.makeManagerNode(beatBytes, TLManagerParameters( - address = Seq(AddressSet(0x1000, 0xfff)))) - // ... - } - - class MyManagerGroup(beatBytes: Int)(implicit p: Parameters) extends LazyModule { - val man1 = LazyModule(new MyManager1(beatBytes)) - val man2 = LazyModule(new MyManager2(beatBytes)) - val node = TLIdentityNode() - - man1.node := node - man2.node := node - } +.. literalinclude:: ../../generators/example/src/main/scala/NodeTypes.scala + :language: scala + :start-after: DOC include start: MyManagerGroup + :end-before: DOC include end: MyManagerGroup If we want to connect the client and manager groups together, we can now do this. -.. code-block:: scala - - class ClientManagerComplex(implicit p: Parameters) extends LazyModule { - val client = LazyModule(new MyClientGroup) - val manager = LazyModule(new MyManagerGroup(8)) - - manager.node :=* client.node - } +.. literalinclude:: ../../generators/example/src/main/scala/NodeTypes.scala + :language: scala + :start-after: DOC include start: MyClientManagerComplex + :end-before: DOC include end: MyClientManagerComplex The meaning of the ``:=*`` operator is explained in more detail in the :ref:`Diplomacy Connectors` section. In summary, it connects two nodes together diff --git a/generators/example/src/main/scala/NodeTypes.scala b/generators/example/src/main/scala/NodeTypes.scala new file mode 100644 index 00000000..577b9baf --- /dev/null +++ b/generators/example/src/main/scala/NodeTypes.scala @@ -0,0 +1,128 @@ +package example + +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import testchipip.TLHelper + +// These modules are not meant to be synthesized. +// They are used as examples in the documentation and are only here +// to check that they compile. + +// DOC include start: MyClient +class MyClient(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeClientNode(TLClientParameters( + name = "my-client", + sourceId = IdRange(0, 4), + requestFifo = true, + visibility = Seq(AddressSet(0x10000, 0xffff)))) + + lazy val module = new LazyModuleImp(this) { + val (tl, edge) = node.out(0) + + // Rest of code here + } +} +// DOC include end: MyClient + +// DOC include start: MyManager +class MyManager(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice("my-device", Seq("tutorial,my-device0")) + val beatBytes = 8 + val node = TLHelper.makeManagerNode(beatBytes, TLManagerParameters( + address = Seq(AddressSet(0x20000, 0xfff)), + resources = device.reg, + regionType = RegionType.UNCACHED, + executable = true, + supportsArithmetic = TransferSizes(1, beatBytes), + supportsLogical = TransferSizes(1, beatBytes), + supportsGet = TransferSizes(1, beatBytes), + supportsPutFull = TransferSizes(1, beatBytes), + supportsPutPartial = TransferSizes(1, beatBytes), + supportsHint = TransferSizes(1, beatBytes), + fifoId = Some(0))) + + lazy val module = new LazyModuleImp(this) { + val (tl, edge) = node.in(0) + } +} +// DOC include end: MyManager + +// DOC include start: MyClient1+MyClient2 +class MyClient1(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeClientNode("my-client1", IdRange(0, 1)) + + lazy val module = new LazyModuleImp(this) { + // ... + } +} + +class MyClient2(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeClientNode("my-client2", IdRange(0, 1)) + + lazy val module = new LazyModuleImp(this) { + // ... + } +} +// DOC include end: MyClient1+MyClient2 + +// DOC include start: MyClientGroup +class MyClientGroup(implicit p: Parameters) extends LazyModule { + val client1 = LazyModule(new MyClient1) + val client2 = LazyModule(new MyClient2) + val node = TLIdentityNode() + + node := client1.node + node := client2.node + + lazy val module = new LazyModuleImp(this) { + // Nothing to do here + } +} +// DOC include end: MyClientGroup + +// DOC include start: MyManagerGroup +class MyManager1(beatBytes: Int)(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeManagerNode(beatBytes, TLManagerParameters( + address = Seq(AddressSet(0x0, 0xfff)))) + + lazy val module = new LazyModuleImp(this) { + // ... + } +} + +class MyManager2(beatBytes: Int)(implicit p: Parameters) extends LazyModule { + val node = TLHelper.makeManagerNode(beatBytes, TLManagerParameters( + address = Seq(AddressSet(0x1000, 0xfff)))) + + lazy val module = new LazyModuleImp(this) { + // ... + } +} + +class MyManagerGroup(beatBytes: Int)(implicit p: Parameters) extends LazyModule { + val man1 = LazyModule(new MyManager1(beatBytes)) + val man2 = LazyModule(new MyManager2(beatBytes)) + val node = TLIdentityNode() + + man1.node := node + man2.node := node + + lazy val module = new LazyModuleImp(this) { + // Nothing to do here + } +} +// DOC include end: MyManagerGroup + +// DOC include start: MyClientManagerComplex +class MyClientManagerComplex(implicit p: Parameters) extends LazyModule { + val client = LazyModule(new MyClientGroup) + val manager = LazyModule(new MyManagerGroup(8)) + + manager.node :=* client.node + + lazy val module = new LazyModuleImp(this) { + // Nothing to do here + } +} +// DOC include end: MyClientManagerComplex From 99fa21348cf9902be1b07191054c5fba9c4e893e Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 16 Sep 2019 10:28:05 -0700 Subject: [PATCH 90/91] move image to _static directory --- docs/Generators/RocketChip.rst | 2 +- docs/{ => _static}/images/rocketchip-diagram.png | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/{ => _static}/images/rocketchip-diagram.png (100%) diff --git a/docs/Generators/RocketChip.rst b/docs/Generators/RocketChip.rst index 34d8f563..b6050534 100644 --- a/docs/Generators/RocketChip.rst +++ b/docs/Generators/RocketChip.rst @@ -11,7 +11,7 @@ out-of-order core generator or some other custom CPU generator instead. A detailed diagram of a typical RocketChip system is shown below. -.. image:: ../images/rocketchip-diagram.png +.. image:: ../_static/images/rocketchip-diagram.png Tiles ----- diff --git a/docs/images/rocketchip-diagram.png b/docs/_static/images/rocketchip-diagram.png similarity index 100% rename from docs/images/rocketchip-diagram.png rename to docs/_static/images/rocketchip-diagram.png From 17f1387846b74bd1d28bce15ba9c39f63d2478b6 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 16 Sep 2019 15:54:32 -0700 Subject: [PATCH 91/91] Fix Sha3RocketConfig ordering --- generators/example/src/main/scala/RocketConfigs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/example/src/main/scala/RocketConfigs.scala b/generators/example/src/main/scala/RocketConfigs.scala index cd78b9d2..5f3164ca 100644 --- a/generators/example/src/main/scala/RocketConfigs.scala +++ b/generators/example/src/main/scala/RocketConfigs.scala @@ -103,10 +103,10 @@ class GB1MemoryRocketConfig extends Config( new freechips.rocketchip.system.BaseConfig) class Sha3RocketConfig extends Config( - new sha3.WithSha3Accel ++ // add SHA3 rocc accelerator new WithTop ++ new WithBootROM ++ new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new sha3.WithSha3Accel ++ // add SHA3 rocc accelerator new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.system.BaseConfig)