From f21658b35e129e3e7561f97b94867fea04298bf0 Mon Sep 17 00:00:00 2001 From: Alex Swehla Date: Mon, 12 Feb 2024 11:25:54 -0800 Subject: [PATCH] Move diplomacy to standalone library absorbing aop Splits out the aop and diplomacy modules into a standalone library. Adds the new library as a dependency and updates the in-tree diplomacy and aop modules to reference the new library with deprecation warnings. --- .gitmodules | 3 + .mill-version | 1 + .scalafmt.conf | 32 + build.sc | 706 +++++--- common.sc | 26 +- dependencies/diplomacy | 1 + src/main/scala/aop/Select.scala | 121 -- src/main/scala/aop/package.scala | 6 + src/main/scala/diplomacy/BundleBridge.scala | 206 --- src/main/scala/diplomacy/Clone.scala | 37 - src/main/scala/diplomacy/LazyModule.scala | 612 ------- src/main/scala/diplomacy/Nodes.scala | 1800 ------------------- src/main/scala/diplomacy/Resources.scala | 332 ++-- src/main/scala/diplomacy/ValName.scala | 12 - src/main/scala/diplomacy/package.scala | 424 +++-- src/main/scala/util/HeterogeneousBag.scala | 24 - src/main/scala/util/package.scala | 120 +- 17 files changed, 1019 insertions(+), 3444 deletions(-) create mode 100644 .mill-version create mode 100644 .scalafmt.conf create mode 160000 dependencies/diplomacy delete mode 100644 src/main/scala/aop/Select.scala create mode 100644 src/main/scala/aop/package.scala delete mode 100644 src/main/scala/diplomacy/BundleBridge.scala delete mode 100644 src/main/scala/diplomacy/Clone.scala delete mode 100644 src/main/scala/diplomacy/LazyModule.scala delete mode 100644 src/main/scala/diplomacy/Nodes.scala delete mode 100644 src/main/scala/diplomacy/ValName.scala delete mode 100644 src/main/scala/util/HeterogeneousBag.scala diff --git a/.gitmodules b/.gitmodules index fa1f58748ff..2fe05e45ed1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "dependencies/chisel"] path = dependencies/chisel url = https://github.com/chipsalliance/chisel.git +[submodule "dependencies/diplomacy"] + path = dependencies/diplomacy + url = https://github.com/lordspacehog/diplomacy.git diff --git a/.mill-version b/.mill-version new file mode 100644 index 00000000000..b80f98e66f1 --- /dev/null +++ b/.mill-version @@ -0,0 +1 @@ +0.11.7 diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 00000000000..358a130b5eb --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,32 @@ +version = 3.7.17 +runner.dialect = scala213 + +maxColumn = 120 +align.preset = most +continuationIndent.defnSite = 2 +assumeStandardLibraryStripMargin = true +docstrings.style = SpaceAsterisk +lineEndings = preserve +includeCurlyBraceInSelectChains = false +danglingParentheses.preset = true + +align.tokens."+" = [ + { + code = ":" + } +] + +newlines.beforeCurlyLambdaParams = never +newlines.beforeMultiline = fold +newlines.implicitParamListModifierForce = [before] + +verticalMultiline.atDefnSite = true + +optIn.annotationNewlines = true + +rewrite.rules = [SortImports, PreferCurlyFors, AvoidInfix] +fileOverride { + "glob:**/common.sc/**" { + runner.dialect = scala3 + } +} diff --git a/build.sc b/build.sc index b19e7a8927d..a45c9d82f55 100644 --- a/build.sc +++ b/build.sc @@ -4,41 +4,39 @@ import mill.scalalib.publish._ import coursier.maven.MavenRepository import $file.dependencies.hardfloat.common import $file.dependencies.cde.common +import $file.dependencies.diplomacy.common import $file.dependencies.chisel.build import $file.common object v { - val scala = "2.13.12" + val scala = "2.13.12" // the first version in this Map is the mainly supported version which will be used to run tests val chiselCrossVersions = Map( - "5.1.0" -> (ivy"org.chipsalliance::chisel:5.1.0", ivy"org.chipsalliance:::chisel-plugin:5.1.0"), + "5.1.0" -> (ivy"org.chipsalliance::chisel:5.1.0", ivy"org.chipsalliance:::chisel-plugin:5.1.0") // build from project from source - "source" -> (ivy"org.chipsalliance::chisel:99", ivy"org.chipsalliance:::chisel-plugin:99"), + // "source" -> (ivy"org.chipsalliance::chisel:99", ivy"org.chipsalliance:::chisel-plugin:99") ) - val mainargs = ivy"com.lihaoyi::mainargs:0.5.0" - val json4sJackson = ivy"org.json4s::json4s-jackson:4.0.5" - val scalaReflect = ivy"org.scala-lang:scala-reflect:${scala}" - val sonatypesSnapshots = Seq( + val mainargs = ivy"com.lihaoyi::mainargs:0.5.0" + val json4sJackson = ivy"org.json4s::json4s-jackson:4.0.5" + val scalaReflect = ivy"org.scala-lang:scala-reflect:${scala}" + val sonatypesSnapshots = Seq( MavenRepository("https://s01.oss.sonatype.org/content/repositories/snapshots") ) + val sourcecode = ivy"com.lihaoyi::sourcecode:0.3.1" } // Build form source only for dev object chisel extends Chisel -trait Chisel - extends millbuild.dependencies.chisel.build.Chisel { - def crossValue = v.scala +trait Chisel extends millbuild.dependencies.chisel.build.Chisel { + def crossValue = v.scala override def millSourcePath = os.pwd / "dependencies" / "chisel" - def scalaVersion = T(v.scala) + def scalaVersion = T(v.scala) } object macros extends Macros -trait Macros - extends millbuild.common.MacrosModule - with RocketChipPublishModule - with SbtModule { +trait Macros extends millbuild.common.MacrosModule with RocketChipPublishModule with SbtModule { def scalaVersion: T[String] = T(v.scala) @@ -48,7 +46,7 @@ trait Macros object hardfloat extends mill.define.Cross[Hardfloat](v.chiselCrossVersions.keys.toSeq) trait Hardfloat - extends millbuild.dependencies.hardfloat.common.HardfloatModule + extends millbuild.dependencies.hardfloat.common.HardfloatModule with RocketChipPublishModule with Cross.Module[String] { @@ -69,20 +67,45 @@ trait Hardfloat object cde extends CDE -trait CDE - extends millbuild.dependencies.cde.common.CDEModule - with RocketChipPublishModule - with ScalaModule { +trait CDE extends millbuild.dependencies.cde.common.CDEModule with RocketChipPublishModule with ScalaModule { def scalaVersion: T[String] = T(v.scala) override def millSourcePath = os.pwd / "dependencies" / "cde" / "cde" } +object diplomacy extends mill.define.Cross[Diplomacy](v.chiselCrossVersions.keys.toSeq) + +trait Diplomacy + extends millbuild.dependencies.diplomacy.common.DiplomacyModule + with RocketChipPublishModule + with Cross.Module[String] { + + override def scalaVersion: T[String] = T(v.scala) + + override def millSourcePath = os.pwd / "dependencies" / "diplomacy" / "diplomacy" + + // dont use chisel from source + def chiselModule = None + def chiselPluginJar = None + + // use chisel from ivy + def chiselIvy = Some(v.chiselCrossVersions(crossValue)._1) + def chiselPluginIvy = Some(v.chiselCrossVersions(crossValue)._2) + + // use CDE from source untill published to sonatype + def cdeModule = Some(cde) + + // no cde ivy currently published + def cdeIvy = None + + def sourcecodeIvy = v.sourcecode +} + object rocketchip extends Cross[RocketChip](v.chiselCrossVersions.keys.toSeq) trait RocketChip - extends millbuild.common.RocketChipModule + extends millbuild.common.RocketChipModule with RocketChipPublishModule with SbtModule with Cross.Module[String] { @@ -104,15 +127,20 @@ trait RocketChip def cdeModule = cde + def diplomacyModule = diplomacy(crossValue) + + def diplomacyIvy = None + def mainargsIvy = v.mainargs def json4sJacksonIvy = v.json4sJackson + def sourcecodeIvy = v.sourcecode + def repositoriesTask = T.task(super.repositoriesTask() ++ v.sonatypesSnapshots) } -trait RocketChipPublishModule - extends PublishModule { +trait RocketChipPublishModule extends PublishModule { def pomSettings = PomSettings( description = artifactName(), organization = "org.chipsalliance", @@ -127,10 +155,9 @@ trait RocketChipPublishModule override def publishVersion: T[String] = T("1.6-SNAPSHOT") } - // Tests trait Emulator extends Cross.Module2[String, String] { - val top: String = crossValue + val top: String = crossValue val config: String = crossValue2 object generator extends Module { @@ -139,9 +166,11 @@ trait Emulator extends Cross.Module2[String, String] { mill.util.Jvm.javaExe, "-jar", rocketchip(v.chiselCrossVersions.keys.head).assembly().path, - "--dir", T.dest.toString, - "--top", top, - config.split('_').flatMap(c => Seq("--config", c)), + "--dir", + T.dest.toString, + "--top", + top, + config.split('_').flatMap(c => Seq("--config", c)) ).call() PathRef(T.dest) } @@ -157,7 +186,8 @@ trait Emulator extends Cross.Module2[String, String] { object mfccompiler extends Module { def compile = T { - os.proc("firtool", + os.proc( + "firtool", generator.chirrtl().path, s"--annotation-file=${generator.chiselAnno().path}", "--disable-annotation-unknown", @@ -172,14 +202,19 @@ trait Emulator extends Cross.Module2[String, String] { } def rtls = T { - os.read(compile().path / "filelist.f").split("\n").map(str => - try { - os.Path(str) - } catch { - case e: IllegalArgumentException if e.getMessage.contains("is not an absolute path") => - compile().path / str.stripPrefix("./") - } - ).filter(p => p.ext == "v" || p.ext == "sv").map(PathRef(_)).toSeq + os.read(compile().path / "filelist.f") + .split("\n") + .map(str => + try { + os.Path(str) + } catch { + case e: IllegalArgumentException if e.getMessage.contains("is not an absolute path") => + compile().path / str.stripPrefix("./") + } + ) + .filter(p => p.ext == "v" || p.ext == "sv") + .map(PathRef(_)) + .toSeq } } @@ -202,8 +237,8 @@ trait Emulator extends Cross.Module2[String, String] { "SimJTAG.cc", "debug_rob.cc", "emulator.cc", - "remote_bitbang.cc", - ).map(c => PathRef(csrcDir().path / c)) + "remote_bitbang.cc" + ).map(c => PathRef(csrcDir().path / c)) } def CMakeListsString = T { @@ -221,7 +256,7 @@ trait Emulator extends Cross.Module2[String, String] { |set(CMAKE_C_COMPILER "clang") |set(CMAKE_CXX_COMPILER "clang++") |set(CMAKE_CXX_FLAGS - |"$${CMAKE_CXX_FLAGS} -DVERILATOR -DTEST_HARNESS=VTestHarness -include VTestHarness.h -include verilator.h -include ${generator.elaborate().path / config + ".plusArgs"}") + |"$${CMAKE_CXX_FLAGS} -DVERILATOR -DTEST_HARNESS=VTestHarness -include VTestHarness.h -include verilator.h -include ${(generator.elaborate().path / config).toString() + ".plusArgs"}") |set(THREADS_PREFER_PTHREAD_FLAG ON) | |find_package(verilator) @@ -267,7 +302,11 @@ trait Emulator extends Cross.Module2[String, String] { } def elf = T.persistent { - mill.util.Jvm.runSubprocess(Seq("cmake", "-G", "Ninja", "-S", cmakefileLists().path, "-B", T.dest.toString).map(_.toString), Map[String, String](), T.dest) + mill.util.Jvm.runSubprocess( + Seq("cmake", "-G", "Ninja", "-S", cmakefileLists().path, "-B", T.dest.toString).map(_.toString), + Map[String, String](), + T.dest + ) mill.util.Jvm.runSubprocess(Seq("ninja", "-C", T.dest).map(_.toString), Map[String, String](), T.dest) PathRef(T.dest / "emulator") } @@ -279,162 +318,390 @@ trait Emulator extends Cross.Module2[String, String] { } /** object to elaborate verilated emulators. */ -object emulator extends Cross[Emulator]( - // RocketSuiteA - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig"), - // RocketSuiteB - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig"), - // RocketSuiteC - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig"), - // Unittest - ("freechips.rocketchip.unittest.TestHarness", "freechips.rocketchip.unittest.AMBAUnitTestConfig"), - ("freechips.rocketchip.unittest.TestHarness", "freechips.rocketchip.unittest.TLSimpleUnitTestConfig"), - ("freechips.rocketchip.unittest.TestHarness", "freechips.rocketchip.unittest.TLWidthUnitTestConfig"), - // DTM - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultRV32Config"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultRV32Config"), - // Miscellaneous - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultSmallConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DualBankConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DualChannelConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DualChannelDualBankConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.RoccExampleConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.Edge128BitConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.Edge32BitConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.QuadChannelBenchmarkConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.EightChannelConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DualCoreConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.MemPortOnlyConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.MMIOPortOnlyConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.CloneTileConfig"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.HypervisorConfig"), - // - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultFP16Config"), -) - -object `runnable-riscv-test` extends mill.Cross[RiscvTest]( - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-ld", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-lh", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-lw", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-sd", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-sh", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-sw", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64si-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64si-p-icache", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ua-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ua-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64uc-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64uc-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ud-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ud-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64uf-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64uf-v", "none"), - // https://github.com/riscv-software-src/riscv-tests/issues/419 - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ui-p", "ma_data"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ui-v", "ma_data"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64um-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64um-v", "none"), - - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64mi-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64mi-p-ld", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64mi-p-lh", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64mi-p-lw", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64mi-p-sd", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64mi-p-sh", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64mi-p-sw", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64si-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64si-p-icache", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64ua-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64ua-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64uc-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64uc-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64ud-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64ud-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64uf-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64uf-v", "none"), - // https://github.com/riscv-software-src/riscv-tests/issues/419 - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64ui-p", "ma_data"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64ui-v", "ma_data"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64um-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig", "rv64um-v", "none"), - - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32mi-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32mi-p-lh", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32mi-p-lw", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32mi-p-sh", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32mi-p-sw", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32si-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32ua-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32ua-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32uc-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32uc-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32uf-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32uf-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32ui-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32ui-v", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32um-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32um-v", "none"), - - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p-lh", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p-lw", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p-sh", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p-sw", "none"), - // lsrc is not implemented if usingDataScratchpad - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32ua-p", "lrsc"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32uc-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32ui-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32um-p", "none"), - - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultFP16Config", "rv64uzfh-p", "none"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultFP16Config", "rv64uzfh-v", "none"), -) - -object `runnable-arch-test` extends mill.Cross[ArchTest]( - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "64", "RV64IMAFDCZicsr_Zifencei"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "32", "RV32IMAFCZicsr_Zifencei"), - // For CI within reasonable time - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "64", "RV64IMACZicsr_Zifencei"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "32", "RV32IMACZicsr_Zifencei"), -) - -object `runnable-jtag-dtm-test` extends mill.Cross[JTAGDTMTest]( - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultConfig", "off", "64", "DebugTest"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultConfig", "off", "64", "MemTest64"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultRV32Config", "off", "32", "DebugTest"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultRV32Config", "off", "32", "MemTest64"), - // SBA - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultConfig", "on", "64", "MemTest64"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultConfig", "on", "64", "MemTest32"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultRV32Config", "on", "32", "MemTest64"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultRV32Config", "on", "32", "MemTest32"), - ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultRV32Config", "on", "32", "MemTest8"), -) +object emulator + extends Cross[Emulator]( + // RocketSuiteA + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig"), + // RocketSuiteB + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultBufferlessConfig"), + // RocketSuiteC + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig"), + // Unittest + ("freechips.rocketchip.unittest.TestHarness", "freechips.rocketchip.unittest.AMBAUnitTestConfig"), + ("freechips.rocketchip.unittest.TestHarness", "freechips.rocketchip.unittest.TLSimpleUnitTestConfig"), + ("freechips.rocketchip.unittest.TestHarness", "freechips.rocketchip.unittest.TLWidthUnitTestConfig"), + // DTM + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultConfig" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultRV32Config" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultConfig" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultRV32Config" + ), + // Miscellaneous + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultSmallConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DualBankConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DualChannelConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DualChannelDualBankConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.RoccExampleConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.Edge128BitConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.Edge32BitConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.QuadChannelBenchmarkConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.EightChannelConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DualCoreConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.MemPortOnlyConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.MMIOPortOnlyConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.CloneTileConfig"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.HypervisorConfig"), + // + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultFP16Config") + ) + +object `runnable-riscv-test` + extends mill.Cross[RiscvTest]( + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-ld", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-lh", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-lw", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-sd", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-sh", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64mi-p-sw", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64si-p", "none"), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultConfig", + "rv64si-p-icache", + "none" + ), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ua-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ua-v", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64uc-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64uc-v", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ud-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ud-v", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64uf-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64uf-v", "none"), + // https://github.com/riscv-software-src/riscv-tests/issues/419 + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ui-p", "ma_data"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64ui-v", "ma_data"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64um-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultConfig", "rv64um-v", "none"), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64mi-p", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64mi-p-ld", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64mi-p-lh", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64mi-p-lw", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64mi-p-sd", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64mi-p-sh", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64mi-p-sw", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64si-p", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64si-p-icache", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64ua-p", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64ua-v", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64uc-p", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64uc-v", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64ud-p", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64ud-v", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64uf-p", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64uf-v", + "none" + ), + // https://github.com/riscv-software-src/riscv-tests/issues/419 + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64ui-p", + "ma_data" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64ui-v", + "ma_data" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64um-p", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultBufferlessConfig", + "rv64um-v", + "none" + ), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32mi-p", "none"), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultRV32Config", + "rv32mi-p-lh", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultRV32Config", + "rv32mi-p-lw", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultRV32Config", + "rv32mi-p-sh", + "none" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultRV32Config", + "rv32mi-p-sw", + "none" + ), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32si-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32ua-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32ua-v", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32uc-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32uc-v", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32uf-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32uf-v", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32ui-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32ui-v", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32um-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultRV32Config", "rv32um-v", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p-lh", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p-lw", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p-sh", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32mi-p-sw", "none"), + // lsrc is not implemented if usingDataScratchpad + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32ua-p", "lrsc"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32uc-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32ui-p", "none"), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.TinyConfig", "rv32um-p", "none"), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultFP16Config", + "rv64uzfh-p", + "none" + ), + ("freechips.rocketchip.system.TestHarness", "freechips.rocketchip.system.DefaultFP16Config", "rv64uzfh-v", "none") + ) + +object `runnable-arch-test` + extends mill.Cross[ArchTest]( + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultConfig", + "64", + "RV64IMAFDCZicsr_Zifencei" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultRV32Config", + "32", + "RV32IMAFCZicsr_Zifencei" + ), + // For CI within reasonable time + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultConfig", + "64", + "RV64IMACZicsr_Zifencei" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.DefaultRV32Config", + "32", + "RV32IMACZicsr_Zifencei" + ) + ) + +object `runnable-jtag-dtm-test` + extends mill.Cross[JTAGDTMTest]( + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultConfig", + "off", + "64", + "DebugTest" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultConfig", + "off", + "64", + "MemTest64" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultRV32Config", + "off", + "32", + "DebugTest" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.DefaultRV32Config", + "off", + "32", + "MemTest64" + ), + // SBA + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultConfig", + "on", + "64", + "MemTest64" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultConfig", + "on", + "64", + "MemTest32" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultRV32Config", + "on", + "32", + "MemTest64" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultRV32Config", + "on", + "32", + "MemTest32" + ), + ( + "freechips.rocketchip.system.TestHarness", + "freechips.rocketchip.system.WithJtagDTMSystem_freechips.rocketchip.system.WithDebugSBASystem_freechips.rocketchip.system.DefaultRV32Config", + "on", + "32", + "MemTest8" + ) + ) // TODO: split below into another file. def envByNameOrRiscv(name: String): String = { sys.env.get(name) match { case Some(value) => value // TODO: if not found, give a warning - case None => sys.env("RISCV") + case None => sys.env("RISCV") } } object `riscv-tests` extends Module { - def testsRoot = - os.Path(envByNameOrRiscv("RISCV_TESTS_ROOT")) / "riscv64-unknown-elf" / "share" / "riscv-tests" + def testsRoot = os.Path(envByNameOrRiscv("RISCV_TESTS_ROOT")) / "riscv64-unknown-elf" / "share" / "riscv-tests" def allCases = T { os.walk(testsRoot).filterNot(p => p.last.endsWith("dump")) } - object suite extends Cross[Suite]( - os.walk(testsRoot).map(_.last).filterNot(_.endsWith("dump")).map(_.split('-').dropRight(1).mkString("-")).filter(_ != "").toSet.toSeq.sorted - ) + object suite + extends Cross[Suite]( + os.walk(testsRoot) + .map(_.last) + .filterNot(_.endsWith("dump")) + .map(_.split('-').dropRight(1).mkString("-")) + .filter(_ != "") + .toSet + .toSeq + .sorted + ) trait Suite extends Cross.Module[String] { val name: String = crossValue @@ -451,20 +718,22 @@ object `riscv-tests` extends Module { // exclude defaults to "none" instead of "" because it is a file name trait RiscvTest extends Cross.Module4[String, String, String, String] { - val top: String = crossValue - val config: String = crossValue2 + val top: String = crossValue + val config: String = crossValue2 val suiteName: String = crossValue3 - val exclude: String = crossValue4 + val exclude: String = crossValue4 def run = T { `riscv-tests`.suite(suiteName).binaries().map { bin => - val name = bin.path.last + val name = bin.path.last val toExclude = exclude.split("-").map(suiteName + "-" + _).exists(_ == name) if (toExclude) { PathRef(T.dest) } else { System.out.println(s"Running: ${emulator(top, config).elf().path} ${bin.path}") - val p = os.proc(emulator(top, config).elf().path, bin.path).call(stdout = T.dest / s"$name.running.log", mergeErrIntoOut = true, check = false) + val p = os + .proc(emulator(top, config).elf().path, bin.path) + .call(stdout = T.dest / s"$name.running.log", mergeErrIntoOut = true, check = false) PathRef(if (p.exitCode != 0) { os.move(T.dest / s"$name.running.log", T.dest / s"$name.failed.log") throw new Exception(s"Test $name failed with exit code ${p.exitCode}") @@ -479,10 +748,10 @@ trait RiscvTest extends Cross.Module4[String, String, String, String] { } trait ArchTest extends Cross.Module4[String, String, String, String] { - val top: String = crossValue + val top: String = crossValue val config: String = crossValue2 - val xlen: String = crossValue3 - val isa: String = crossValue4 + val xlen: String = crossValue3 + val isa: String = crossValue4 def ispecString = T { // format: off @@ -519,7 +788,8 @@ trait ArchTest extends Cross.Module4[String, String, String, String] { def CC = T { sys.env.get("RV64_TOOLCHAIN_ROOT") match { case Some(value) => value + "/bin/riscv64-none-elf-gcc" // nix uses a different name - case None => sys.env("RISCV") + "/bin/riscv64-unknown-elf-gcc" // if not found, throws NoSuchElementException exception + case None => + sys.env("RISCV") + "/bin/riscv64-unknown-elf-gcc" // if not found, throws NoSuchElementException exception } } @@ -589,13 +859,16 @@ trait ArchTest extends Cross.Module4[String, String, String, String] { def run = T { src() copy() - os.proc("riscof", "run", "--no-browser", + os.proc( + "riscof", + "run", + "--no-browser", s"--config=${configIni().path / "config.ini"}", "--suite=riscv-arch-test/riscv-test-suite/", "--env=riscv-arch-test/riscv-test-suite/env" ).call(home().path) val reportFile = configIni().path / "riscof_work" / "report.html" - val report = os.read(reportFile) + val report = os.read(reportFile) if (report.contains("0Failed")) { System.out.println(s"Arch Test $top $config $xlen $isa Succeeded") } else { @@ -605,32 +878,35 @@ trait ArchTest extends Cross.Module4[String, String, String, String] { } trait JTAGDTMTest extends Cross.Module5[String, String, String, String, String] { - val top: String = crossValue + val top: String = crossValue val config: String = crossValue2 - val sba: String = crossValue3 - val xlen: String = crossValue4 - val name: String = crossValue5 + val sba: String = crossValue3 + val xlen: String = crossValue4 + val name: String = crossValue5 def run = T { val gdbserver = os.Path(sys.env.get("RISCV_TESTS_ROOT").get) / "debug" / "gdbserver.py" - val p = os.proc( - gdbserver, - "--print-failures", - "--print-log-names", - s"--sim_cmd=${emulator(top, config).elf().path} +jtag_rbb_enable=1 dummybin", - "--server_cmd=openocd", - "--gdb=riscv64-none-elf-gdb", - s"--${xlen}", - s"./scripts/RocketSim${xlen}.py", - name, - ).call( - env = Map( - "TERM" -> "", // otherwise readline issues on bracketed-paste - "JTAG_DTM_ENABLE_SBA" -> sba, - ), - stdout = T.dest / s"$name.running.log", - mergeErrIntoOut = true, - check = false) + val p = os + .proc( + gdbserver, + "--print-failures", + "--print-log-names", + s"--sim_cmd=${emulator(top, config).elf().path} +jtag_rbb_enable=1 dummybin", + "--server_cmd=openocd", + "--gdb=riscv64-none-elf-gdb", + s"--${xlen}", + s"./scripts/RocketSim${xlen}.py", + name + ) + .call( + env = Map( + "TERM" -> "", // otherwise readline issues on bracketed-paste + "JTAG_DTM_ENABLE_SBA" -> sba + ), + stdout = T.dest / s"$name.running.log", + mergeErrIntoOut = true, + check = false + ) PathRef(if (p.exitCode != 0) { os.move(T.dest / s"$name.running.log", T.dest / s"$name.failed.log") throw new Exception(s"Test $name failed with exit code ${p.exitCode}") diff --git a/common.sc b/common.sc index 574f0ad4310..e09725e3fd7 100644 --- a/common.sc +++ b/common.sc @@ -1,8 +1,7 @@ import mill._ import mill.scalalib._ -trait HasChisel - extends ScalaModule { +trait HasChisel extends ScalaModule { // Define these for building chisel from source def chiselModule: Option[ScalaModule] @@ -21,20 +20,18 @@ trait HasChisel def chiselPluginIvy: Option[Dep] - override def scalacPluginIvyDeps: T[Agg[Dep]] = T(super.scalacPluginIvyDeps() ++ chiselPluginIvy.map(Agg(_)).getOrElse(Agg.empty[Dep])) + override def scalacPluginIvyDeps: T[Agg[Dep]] = + T(super.scalacPluginIvyDeps() ++ chiselPluginIvy.map(Agg(_)).getOrElse(Agg.empty[Dep])) } -trait MacrosModule - extends ScalaModule { +trait MacrosModule extends ScalaModule { def scalaReflectIvy: Dep override def ivyDeps = T(super.ivyDeps() ++ Some(scalaReflectIvy)) } - -trait RocketChipModule - extends HasChisel { +trait RocketChipModule extends HasChisel { override def mainClass = T(Some("freechips.rocketchip.diplomacy.Main")) def macrosModule: MacrosModule @@ -45,16 +42,23 @@ trait RocketChipModule // should be cde/common.sc#CDEModule def cdeModule: ScalaModule + def diplomacyModule: ScalaModule + + def diplomacyIvy: Option[Dep] + def mainargsIvy: Dep def json4sJacksonIvy: Dep - override def moduleDeps = super.moduleDeps ++ Seq(macrosModule, hardfloatModule, cdeModule) + def sourcecodeIvy: Dep + + override def moduleDeps = super.moduleDeps ++ Seq(macrosModule, hardfloatModule, cdeModule, diplomacyModule) override def ivyDeps = T( super.ivyDeps() ++ Agg( mainargsIvy, - json4sJacksonIvy - ) + json4sJacksonIvy, + sourcecodeIvy + ) ++ diplomacyIvy ) } diff --git a/dependencies/diplomacy b/dependencies/diplomacy new file mode 160000 index 00000000000..b4f93b7747e --- /dev/null +++ b/dependencies/diplomacy @@ -0,0 +1 @@ +Subproject commit b4f93b7747e59376e65e11d83982f5b865d7e6f6 diff --git a/src/main/scala/aop/Select.scala b/src/main/scala/aop/Select.scala deleted file mode 100644 index 132b859ed12..00000000000 --- a/src/main/scala/aop/Select.scala +++ /dev/null @@ -1,121 +0,0 @@ -// See LICENSE.SiFive for license details. - -package freechips.rocketchip.aop - -import chisel3.Data -import org.chipsalliance.cde.config.Parameters -import freechips.rocketchip.diplomacy.{ - AnyMixedNode, - BaseNode, - InwardNode, - LazyModule, - MixedNode, - OutwardNode, -} - -/** Combinators for finding specific sets of [[LazyModule]]s/[[Node]]s. - * - * These can be used for e.g. finding specific TLBundles in a design and - * placing monitors or annotating metadata. - */ -object Select { - - /** Contains information about an inward edge of a node - */ - case class InwardEdge[Bundle <: Data, EdgeInParams]( - params: Parameters, - bundle: Bundle, - edge: EdgeInParams, - node: OutwardNode[_, _, Bundle], - ) - - /** Contains information about an outward edge of a node - */ - case class OutwardEdge[Bundle <: Data, EdgeOutParams]( - params: Parameters, - bundle: Bundle, - edge: EdgeOutParams, - node: InwardNode[_, _, Bundle], - ) - - /** Collects the [[InwardEdge]]s of a node. Defined as a separate method so - * that the bundle/edge types can be set properly - */ - private def getInwardEdges[BI <: Data, EI](node: MixedNode[_, _, EI, BI, _, _, _, _ <: Data]): Iterable[InwardEdge[BI, EI]] = { - node.iPorts.zip(node.in).map { - case ((_, node, params, _), (bundle, edge)) => - InwardEdge(params, bundle, edge, node) - } - } - - /** Applies the collect function to each [[InwardEdge]] of a node - */ - def collectInwardEdges[T](node: BaseNode)(collect: PartialFunction[InwardEdge[_ <: Data, _], T]): Iterable[T] = { - node match { - case node: AnyMixedNode => getInwardEdges(node).collect(collect) - case _ => Seq.empty - } - } - - /** Collects the [[OutwardEdge]]s of a node. Defined as a separate method so - * that the bundle/edge types can be set properly - */ - private def getOutwardEdges[BO <: Data, EO](node: MixedNode[_, _, _, _ <: Data, _, _, EO, BO]): Iterable[OutwardEdge[BO, EO]] = { - node.oPorts.zip(node.out).map { - case ((_, node, params, _), (bundle, edge)) => - OutwardEdge(params, bundle, edge, node) - } - } - - /** Applies the collect function to each [[OutardEdge]] of a node - */ - def collectOutwardEdges[T](node: BaseNode)(collect: PartialFunction[OutwardEdge[_ <: Data, _], T]): Iterable[T] = { - node match { - case node: AnyMixedNode => getOutwardEdges(node).collect(collect) - case _ => Seq.empty - } - } - - /** Applies the collect function to a [[LazyModule]] and recursively to all - * of its children. - */ - def collectDeep[T](lmod: LazyModule)(collect: PartialFunction[LazyModule, T]): Iterable[T] = { - collect.lift(lmod) ++ - lmod.getChildren.flatMap { child => - collectDeep(child)(collect) - } - } - - /** Applies the collect function to a [[LazyModule]] and its children if the - * filter function returns true. Stops recursing when the filter function - * returns false. e.g. - * for this hierarchy - * A - * / \ - * B C - * / \ \ - * D E F - * - * the following select function - * {{{ - * filterCollectDeep(A) { - * case B => false - * case _ => true - * } { m => - * printl(m) - * } - * }}} - * - * will only print modules A, C, and F - */ - def filterCollectDeep[T](lmod: LazyModule)(filter: LazyModule => Boolean)(collect: PartialFunction[LazyModule, T]): Iterable[T] = { - if (filter(lmod)) { - collect.lift(lmod) ++ - lmod.getChildren.flatMap { child => - filterCollectDeep(child)(filter)(collect) - } - } else { - Iterable.empty - } - } -} diff --git a/src/main/scala/aop/package.scala b/src/main/scala/aop/package.scala new file mode 100644 index 00000000000..a773e153552 --- /dev/null +++ b/src/main/scala/aop/package.scala @@ -0,0 +1,6 @@ +package freechips.rocketchip + +object aop { + @deprecated("aop has moved to the standalone diplomacy library.", "rocketchip 2.0.0") + val Select = _root_.org.chipsalliance.diplomacy.aop.Select +} diff --git a/src/main/scala/diplomacy/BundleBridge.scala b/src/main/scala/diplomacy/BundleBridge.scala deleted file mode 100644 index 39ba091ac94..00000000000 --- a/src/main/scala/diplomacy/BundleBridge.scala +++ /dev/null @@ -1,206 +0,0 @@ -// See LICENSE.SiFive for license details. - -package freechips.rocketchip.diplomacy - -import chisel3._ -import chisel3.experimental.SourceInfo -import chisel3.reflect.DataMirror -import chisel3.reflect.DataMirror.internal.chiselTypeClone -import org.chipsalliance.cde.config.Parameters -import freechips.rocketchip.util.DataToAugmentedData - -case class BundleBridgeParams[T <: Data](genOpt: Option[() => T]) - -case object BundleBridgeParams { - def apply[T <: Data](gen: () => T): BundleBridgeParams[T] = BundleBridgeParams(Some(gen)) -} - -case class BundleBridgeEdgeParams[T <: Data](source: BundleBridgeParams[T], sink: BundleBridgeParams[T]) - -class BundleBridgeImp[T <: Data]() extends SimpleNodeImp[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T] -{ - def edge(pd: BundleBridgeParams[T], pu: BundleBridgeParams[T], p: Parameters, sourceInfo: SourceInfo) = BundleBridgeEdgeParams(pd, pu) - def bundle(e: BundleBridgeEdgeParams[T]): T = { - val sourceOpt = e.source.genOpt.map(_()) - val sinkOpt = e.sink.genOpt.map(_()) - (sourceOpt, sinkOpt) match { - case (None, None) => - throw new Exception("BundleBridge needs source or sink to provide bundle generator function") - case (Some(a), None) => chiselTypeClone(a) - case (None, Some(b)) => chiselTypeClone(b) - case (Some(a), Some(b)) => { - require(DataMirror.checkTypeEquivalence(a, b), - s"BundleBridge requires doubly-specified source and sink generators to have equivalent Chisel Data types, but got \n$a\n vs\n$b") - chiselTypeClone(a) - } - } - } - def render(e: BundleBridgeEdgeParams[T]) = RenderedEdge(colour = "#cccc00" /* yellow */) -} - -case class BundleBridgeSink[T <: Data](genOpt: Option[() => T] = None) - (implicit valName: ValName) - extends SinkNode(new BundleBridgeImp[T])(Seq(BundleBridgeParams(genOpt))) -{ - def bundle: T = in(0)._1 - - private def inferOutput = bundle.getElements.forall { elt => - DataMirror.directionOf(elt) == ActualDirection.Unspecified - } - - def makeIO()(implicit valName: ValName): T = { - val io: T = IO(if (inferOutput) Output(chiselTypeOf(bundle)) else chiselTypeClone(bundle)) - io.suggestName(valName.name) - io <> bundle - io - } - def makeIO(name: String): T = makeIO()(ValName(name)) -} - -object BundleBridgeSink { - def apply[T <: Data]()(implicit valName: ValName): BundleBridgeSink[T] = { - BundleBridgeSink(None) - } -} - -case class BundleBridgeSource[T <: Data](genOpt: Option[() => T] = None)(implicit valName: ValName) extends SourceNode(new BundleBridgeImp[T])(Seq(BundleBridgeParams(genOpt))) -{ - def bundle: T = out(0)._1 - - private def inferInput = bundle.getElements.forall { elt => - DataMirror.directionOf(elt) == ActualDirection.Unspecified - } - - def makeIO()(implicit valName: ValName): T = { - val io: T = IO(if (inferInput) Input(chiselTypeOf(bundle)) else Flipped(chiselTypeClone(bundle))) - io.suggestName(valName.name) - bundle <> io - io - } - def makeIO(name: String): T = makeIO()(ValName(name)) - - private var doneSink = false - def makeSink()(implicit p: Parameters) = { - require (!doneSink, "Can only call makeSink() once") - doneSink = true - val sink = BundleBridgeSink[T]() - sink := this - sink - } -} - -object BundleBridgeSource { - def apply[T <: Data]()(implicit valName: ValName): BundleBridgeSource[T] = { - BundleBridgeSource(None) - } - def apply[T <: Data](gen: () => T)(implicit valName: ValName): BundleBridgeSource[T] = { - BundleBridgeSource(Some(gen)) - } -} - -case class BundleBridgeIdentityNode[T <: Data]()(implicit valName: ValName) extends IdentityNode(new BundleBridgeImp[T])() -case class BundleBridgeEphemeralNode[T <: Data]()(implicit valName: ValName) extends EphemeralNode(new BundleBridgeImp[T])() - -object BundleBridgeNameNode { - def apply[T <: Data](name: String) = BundleBridgeIdentityNode[T]()(ValName(name)) -} - -case class BundleBridgeNexusNode[T <: Data](default: Option[() => T] = None, - inputRequiresOutput: Boolean = false) // when false, connecting a source does not mandate connecting a sink - (implicit valName: ValName) - extends NexusNode(new BundleBridgeImp[T])( - dFn = seq => seq.headOption.getOrElse(BundleBridgeParams(default)), - uFn = seq => seq.headOption.getOrElse(BundleBridgeParams(None)), - inputRequiresOutput = inputRequiresOutput, - outputRequiresInput = !default.isDefined) - -class BundleBridgeNexus[T <: Data]( - inputFn: Seq[T] => T, - outputFn: (T, Int) => Seq[T], - default: Option[() => T] = None, - inputRequiresOutput: Boolean = false, - override val shouldBeInlined: Boolean = true -) (implicit p: Parameters) extends LazyModule -{ - val node = BundleBridgeNexusNode[T](default, inputRequiresOutput) - - lazy val module = new Impl - class Impl extends LazyRawModuleImp(this) { - val defaultWireOpt = default.map(_()) - val inputs: Seq[T] = node.in.map(_._1) - inputs.foreach { i => require(DataMirror.checkTypeEquivalence(i, inputs.head), - s"${node.context} requires all inputs have equivalent Chisel Data types, but got\n$i\nvs\n${inputs.head}") - } - inputs.flatMap(_.getElements).foreach { elt => DataMirror.directionOf(elt) match { - case ActualDirection.Output => () - case ActualDirection.Unspecified => () - case _ => require(false, s"${node.context} can only be used with Output-directed Bundles") - } } - - val outputs: Seq[T] = if (node.out.size > 0) { - val broadcast: T = if (inputs.size >= 1) inputFn(inputs) else defaultWireOpt.get - outputFn(broadcast, node.out.size) - } else { Nil } - - node.out.map(_._1).foreach { o => require(DataMirror.checkTypeEquivalence(o, outputs.head), - s"${node.context} requires all outputs have equivalent Chisel Data types, but got\n$o\nvs\n${outputs.head}") - } - - require(outputs.size == node.out.size, - s"${node.context} outputFn must generate one output wire per edgeOut, but got ${outputs.size} vs ${node.out.size}") - - node.out.zip(outputs).foreach { case ((out, _), bcast) => out := bcast } - } -} - -object BundleBridgeNexus { - def safeRegNext[T <: Data](x: T): T = { - val reg = Reg(chiselTypeOf(x)) - reg := x - reg - } - - def requireOne[T <: Data](registered: Boolean)(seq: Seq[T]): T = { - require(seq.size == 1, "BundleBroadcast default requires one input") - if (registered) safeRegNext(seq.head) else seq.head - } - - def orReduction[T <: Data](registered: Boolean)(seq: Seq[T]): T = { - val x = seq.reduce((a,b) => (a.asUInt | b.asUInt).asTypeOf(seq.head)) - if (registered) safeRegNext(x) else x - } - - def fillN[T <: Data](registered: Boolean)(x: T, n: Int): Seq[T] = Seq.fill(n) { - if (registered) safeRegNext(x) else x - } - - def apply[T <: Data]( - inputFn: Seq[T] => T = orReduction[T](false) _, - outputFn: (T, Int) => Seq[T] = fillN[T](false) _, - default: Option[() => T] = None, - inputRequiresOutput: Boolean = false, - shouldBeInlined: Boolean = true - )(implicit p: Parameters): BundleBridgeNexusNode[T] = { - val nexus = LazyModule(new BundleBridgeNexus[T](inputFn, outputFn, default, inputRequiresOutput, shouldBeInlined)) - nexus.node - } -} - -object BundleBroadcast { - def apply[T <: Data]( - name: Option[String] = None, - registered: Boolean = false, - default: Option[() => T] = None, - inputRequiresOutput: Boolean = false, // when false, connecting a source does not mandate connecting a sink - shouldBeInlined: Boolean = true - )(implicit p: Parameters): BundleBridgeNexusNode[T] = { - val broadcast = LazyModule(new BundleBridgeNexus[T]( - inputFn = BundleBridgeNexus.requireOne[T](registered) _, - outputFn = BundleBridgeNexus.fillN[T](registered) _, - default = default, - inputRequiresOutput = inputRequiresOutput, - shouldBeInlined = shouldBeInlined)) - name.foreach(broadcast.suggestName(_)) - broadcast.node - } -} diff --git a/src/main/scala/diplomacy/Clone.scala b/src/main/scala/diplomacy/Clone.scala deleted file mode 100644 index 4e0b9209d65..00000000000 --- a/src/main/scala/diplomacy/Clone.scala +++ /dev/null @@ -1,37 +0,0 @@ -// See LICENSE.SiFive for license details. - -package freechips.rocketchip.diplomacy - -import chisel3._ -import chisel3.experimental.{CloneModuleAsRecord, SourceInfo} - -final class CloneLazyModule private (val base: LazyModule) -{ - // Pay special attention to the .iParams and .oParams of the node, which - // indicate the parameters a stand-in master must supply. - def clone[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](node: NodeHandle[DI, UI, EI, BI, DO, UO, EO, BO])(implicit valName: ValName) = - new MixedTestNode(node, this) - - protected[diplomacy] lazy val io = CloneModuleAsRecord(base.module) -} - -object CloneLazyModule -{ - /** The old API **/ - def apply(base: LazyModule) = new CloneLazyModule(base) - - - /** Constructs a [[LazyModule]], but replaces its [[LazyModuleImp]] with a cloned [[LazyModuleImp]] - * from another source. The user of [[CloneLazyModule]] must be careful to guarantee that - * bc and cloneProto have equivalent [[LazyModuleImp]]'s. - * - * @param bc [[LazyModule]] instance to wrap, this instance will not evaluate its own [[LazyModuleImp]] - * @param cloneProto [[LazyModule]] instance which will provide the [[LazyModuleImp]] implementation for bc - */ - def apply[A <: LazyModule, B <: LazyModule](bc: A, cloneProto: B)(implicit valName: ValName, sourceInfo: SourceInfo): A = { - require(LazyModule.scope.isDefined, s"CloneLazyModule ${bc.name} ${sourceLine(sourceInfo)} can only exist as the child of a parent LazyModule") - LazyModule(bc) - bc.cloneProto = Some(cloneProto) - bc - } -} diff --git a/src/main/scala/diplomacy/LazyModule.scala b/src/main/scala/diplomacy/LazyModule.scala deleted file mode 100644 index ff6e0378762..00000000000 --- a/src/main/scala/diplomacy/LazyModule.scala +++ /dev/null @@ -1,612 +0,0 @@ -// See LICENSE.SiFive for license details. - -package freechips.rocketchip.diplomacy - -import chisel3._ -import chisel3.{Module, RawModule, Reset, withClockAndReset} -import chisel3.experimental.{ChiselAnnotation, CloneModuleAsRecord, SourceInfo, UnlocatableSourceInfo} -import firrtl.passes.InlineAnnotation -import org.chipsalliance.cde.config.Parameters - -import scala.collection.immutable.{SeqMap, SortedMap} -import scala.util.matching._ - -/** While the [[freechips.rocketchip.diplomacy]] package allows fairly abstract parameter negotiation while constructing a DAG, - * [[LazyModule]] builds on top of the DAG annotated with the negotiated parameters and leverage's Scala's lazy evaluation property to split Chisel module generation into two phases: - * - * - Phase 1 (diplomatic) states parameters, hierarchy, and connections: - * - [[LazyModule]] and [[BaseNode]] instantiation. - * - [[BaseNode]] binding. - * - Phase 2 (lazy) generates [[chisel3]] Modules: - * - Parameters are negotiated across [[BaseNode]]s. - * - Concrete [[Bundle]]s are created along [[BaseNode]]s and connected - * - [[AutoBundle]] are automatically connected along [[Edges]], punching IO as necessary though module hierarchy - * - [[LazyModuleImpLike]] generates [[chisel3.Module]]s. - */ -abstract class LazyModule()(implicit val p: Parameters) { - /** Contains sub-[[LazyModule]]s; can be accessed by [[getChildren]]. */ - protected[diplomacy] var children: List[LazyModule] = List[LazyModule]() - /** Contains the [[BaseNode]]s instantiated within this instance. */ - protected[diplomacy] var nodes: List[BaseNode] = List[BaseNode]() - /** Stores [[SourceInfo]] of this instance. - * - * The companion object factory method will set this to the correct value. - */ - protected[diplomacy] var info: SourceInfo = UnlocatableSourceInfo - /** Parent of this LazyModule. If this instance is at the top of the hierarchy, this will be [[None]]. */ - protected[diplomacy] val parent: Option[LazyModule] = LazyModule.scope - /** If set, the LazyModule this LazyModule will be a clone of - * Note that children of a cloned module will also have this set - */ - protected[diplomacy] var cloneProto: Option[LazyModule] = None - - /** Code snippets from [[InModuleBody]] injection. */ - protected[diplomacy] var inModuleBody: List[() => Unit] = List[() => Unit]() - - /** Sequence of ancestor LazyModules, starting with [[parent]]. */ - def parents: Seq[LazyModule] = parent match { - case None => Nil - case Some(x) => x +: x.parents - } - - // Push this instance onto the [[LazyModule.scope]] stack. - LazyModule.scope = Some(this) - parent.foreach(p => p.children = this :: p.children) - - /** Accumulates Some(names), taking the final one. `None`s are ignored. */ - private var suggestedNameVar: Option[String] = None - - /** Suggests instance name for [[LazyModuleImpLike]] module. */ - def suggestName(x: String): this.type = suggestName(Some(x)) - - def suggestName(x: Option[String]): this.type = { - x.foreach { n => suggestedNameVar = Some(n) } - this - } - - /** Finds the name of the first non-anonymous Scala class while walking up the class hierarchy. */ - private def findClassName(c: Class[_]): String = { - val n = c.getName.split('.').last - if (n.contains('$')) findClassName(c.getSuperclass) else n - } - - /** Scala class name of this instance. */ - lazy val className: String = findClassName(getClass) - /** Suggested instance name. Defaults to [[className]].*/ - lazy val suggestedName: String = suggestedNameVar.getOrElse(className) - /** Suggested module name. Defaults to [[className]].*/ - lazy val desiredName: String = className // + hashcode? - - /** Return instance name. */ - def name: String = suggestedName // className + suggestedName ++ hashcode ? - /** Return source line that defines this instance. */ - def line: String = sourceLine(info) - - // Accessing these names can only be done after circuit elaboration! - /** Module name in verilog, used in GraphML. - * For cloned lazyModules, this is the name of the prototype - */ - lazy val moduleName: String = cloneProto.map(_.module.name).getOrElse(module.name) - /** Hierarchical path of this instance, used in GraphML. - * For cloned modules, construct this manually (since this.module should not be evaluated) - */ - lazy val pathName: String = cloneProto.map(p => s"${parent.get.pathName}.${p.instanceName}") - .getOrElse(module.pathName) - - /** Instance name in verilog. Should only be accessed after circuit elaboration. */ - lazy val instanceName: String = pathName.split('.').last - - /** [[chisel3]] hardware implementation of this [[LazyModule]]. - * - * Subclasses should define this function as `lazy val`s for lazy evaluation. - * Generally, the evaluation of this marks the beginning of phase 2. - */ - def module: LazyModuleImpLike - - /** Recursively traverse all child LazyModules and Nodes of this LazyModule - * to construct the set of empty [[Dangle]]'s that are this module's top-level IO - * This is effectively doing the same thing as [[LazyModuleImp.instantiate]], but - * without constructing any [[Module]]'s - */ - protected[diplomacy] def cloneDangles(): List[Dangle] = { - children.foreach(c => require(c.cloneProto.isDefined, s"${c.info}, ${c.parent.get.info}")) - val childDangles = children.reverse.flatMap { c => c.cloneDangles() } - val nodeDangles = nodes.reverse.flatMap(n => n.cloneDangles()) - val allDangles = nodeDangles ++ childDangles - val pairing = SortedMap(allDangles.groupBy(_.source).toSeq: _*) - val done = Set() ++ pairing.values.filter(_.size == 2).map { - case Seq(a, b) => - require(a.flipped != b.flipped) - a.source - case _ => - None - } - val forward = allDangles.filter(d => !done(d.source)) - val dangles = forward.map { d => - d.copy(name = suggestedName + "_" + d.name) - } - dangles - } - - /** Whether to omit generating the GraphML for this [[LazyModule]]. - * - * Recursively checks whether all [[BaseNode]]s and children [[LazyModule]]s should omit GraphML - * generation. - */ - def omitGraphML: Boolean = nodes.forall(_.omitGraphML) && children.forall(_.omitGraphML) - - /** Whether this [[LazyModule]]'s module should be marked for in-lining by FIRRTL. - * - * The default heuristic is to inline any parents whose children have been inlined - * and whose nodes all produce identity circuits. - */ - def shouldBeInlined: Boolean = nodes.forall(_.circuitIdentity) && children.forall(_.shouldBeInlined) - - /** GraphML representation for this instance. - * - * This is a representation of the Nodes, Edges, LazyModule hierarchy, - * and any other information that is added in by implementations. - * It can be converted to an image with various third-party tools. - */ - lazy val graphML: String = parent.map(_.graphML).getOrElse { - val buf = new StringBuilder - buf ++= "\n" - buf ++= "\n" - buf ++= " \n" - buf ++= " \n" - buf ++= " \n" - buf ++= " \n" - nodesGraphML(buf, " ") - edgesGraphML(buf, " ") - buf ++= " \n" - buf ++= "\n" - buf.toString - } - - /** A globally unique [[LazyModule]] index for this instance. */ - private val index = { - LazyModule.index = LazyModule.index + 1 - LazyModule.index - } - - /** Generate GraphML fragment for nodes. - * - * @param buf String buffer to write to. - * @param pad Padding as prefix for indentation purposes. - */ - private def nodesGraphML(buf: StringBuilder, pad: String): Unit = { - buf ++= s"""$pad\n""" - buf ++= s"""$pad $instanceName\n""" - buf ++= s"""$pad $moduleName ($pathName)\n""" - buf ++= s"""$pad \n""" - nodes.filter(!_.omitGraphML).foreach { n => - buf ++= s"""$pad \n""" - buf ++= s"""$pad \n""" - buf ++= s"""$pad ${n.formatNode}, \n${n.nodedebugstring}\n""" - buf ++= s"""$pad \n""" - } - children.filter(!_.omitGraphML).foreach(_.nodesGraphML(buf, pad + " ")) - buf ++= s"""$pad \n""" - buf ++= s"""$pad\n""" - } - - /** Generate GraphML fragment for edges. - * - * @param buf String buffer to write to. - * @param pad Padding as prefix for indentation purposes. - */ - private def edgesGraphML(buf: StringBuilder, pad: String): Unit = { - nodes.filter(!_.omitGraphML) foreach { n => - n.outputs.filter(!_._1.omitGraphML).foreach { case (o, edge) => - val RenderedEdge(colour, label, flipped) = edge - buf ++= pad - buf ++= """" - } else { - buf ++= s""" source=\"$index::${n.index}\"""" - buf ++= s""" target=\"${o.lazyModule.index}::${o.index}\">""" - } - buf ++= s"""""" - if (flipped) { - buf ++= s"""""" - } else { - buf ++= s"""""" - } - buf ++= s"""""" - buf ++= s"""$label""" - buf ++= s"""\n""" - } - } - children.filter(!_.omitGraphML).foreach { c => c.edgesGraphML(buf, pad) } - } - - /** Call function on all of this [[LazyModule]]'s [[children]]. - * - * @param iterfunc Function to call on each descendant. - */ - def childrenIterator(iterfunc: LazyModule => Unit): Unit = { - iterfunc(this) - children.foreach(_.childrenIterator(iterfunc)) - } - - /** Call function on all of this [[LazyModule]]'s [[nodes]]. - * - * @param iterfunc Function to call on each descendant. - */ - def nodeIterator(iterfunc: BaseNode => Unit): Unit = { - nodes.foreach(iterfunc) - childrenIterator(_.nodes.foreach(iterfunc)) - } - - /** Accessor for [[children]]. */ - def getChildren: List[LazyModule] = children - - /** Accessor for [[nodes]]. */ - def getNodes: List[BaseNode] = nodes -} - -object LazyModule { - /** Current [[LazyModule]] scope. The scope is a stack of [[LazyModule]]/[[LazyScope]]s. - * - * Each call to [[LazyScope.apply]] or [[LazyModule.apply]] will push that item onto the current scope. - */ - protected[diplomacy] var scope: Option[LazyModule] = None - /** Global index of [[LazyModule]]. Note that there is no zeroth module. */ - private var index = 0 - - /** Wraps a [[LazyModule]], handling bookkeeping of scopes. - * - * This method manages the scope and index of the [[LazyModule]]s. All [[LazyModule]]s must be - * wrapped exactly once. - * - * @param bc [[LazyModule]] instance to be wrapped. - * @param valName [[ValName]] used to name this instance, - * it can be automatically generated by [[ValName]] macro, or specified manually. - * @param sourceInfo [[SourceInfo]] information about where this [[LazyModule]] is being generated - */ - def apply[T <: LazyModule](bc: T)(implicit valName: ValName, sourceInfo: SourceInfo): T = { - // Make sure the user puts [[LazyModule]] around modules in the correct order. - require(scope.isDefined, s"LazyModule() applied to ${bc.name} twice ${sourceLine(sourceInfo)}. Ensure that descendant LazyModules are instantiated with the LazyModule() wrapper and that you did not call LazyModule() twice.") - require(scope.get eq bc, s"LazyModule() applied to ${bc.name} before ${scope.get.name} ${sourceLine(sourceInfo)}") - // Pop from the [[LazyModule.scope]] stack. - scope = bc.parent - bc.info = sourceInfo - if (bc.suggestedNameVar.isEmpty) bc.suggestName(valName.name) - bc - } -} - -/** Trait describing the actual [[Module]] implementation wrapped by a [[LazyModule]]. - * - * This is the actual Chisel module that is lazily-evaluated in the second phase of Diplomacy. - */ -sealed trait LazyModuleImpLike extends RawModule { - /** [[LazyModule]] that contains this instance. */ - val wrapper: LazyModule - /** IOs that will be automatically "punched" for this instance. */ - val auto: AutoBundle - /** The metadata that describes the [[HalfEdge]]s which generated [[auto]]. */ - protected[diplomacy] val dangles: Seq[Dangle] - - // [[wrapper.module]] had better not be accessed while LazyModules are still being built! - require(LazyModule.scope.isEmpty, s"${wrapper.name}.module was constructed before LazyModule() was run on ${LazyModule.scope.get.name}") - - /** Set module name. Defaults to the containing LazyModule's desiredName.*/ - override def desiredName: String = wrapper.desiredName - - suggestName(wrapper.suggestedName) - - /** [[Parameters]] for chisel [[Module]]s. */ - implicit val p: Parameters = wrapper.p - - /** instantiate this [[LazyModule]], - * return [[AutoBundle]] and a unconnected [[Dangle]]s from this module and submodules. */ - protected[diplomacy] def instantiate(): (AutoBundle, List[Dangle]) = { - // 1. It will recursively append [[wrapper.children]] into [[chisel3.internal.Builder]], - // 2. return [[Dangle]]s from each module. - val childDangles = wrapper.children.reverse.flatMap { c => - implicit val sourceInfo: SourceInfo = c.info - c.cloneProto.map { cp => - // If the child is a clone, then recursively set cloneProto of its children as well - def assignCloneProtos(bases: Seq[LazyModule], clones: Seq[LazyModule]): Unit = { - require(bases.size == clones.size) - (bases zip clones).map { case (l,r) => - require(l.getClass == r.getClass, s"Cloned children class mismatch ${l.name} != ${r.name}") - l.cloneProto = Some(r) - assignCloneProtos(l.children, r.children) - } - } - assignCloneProtos(c.children, cp.children) - // Clone the child module as a record, and get its [[AutoBundle]] - val clone = CloneModuleAsRecord(cp.module).suggestName(c.suggestedName) - val clonedAuto = clone("auto").asInstanceOf[AutoBundle] - // Get the empty [[Dangle]]'s of the cloned child - val rawDangles = c.cloneDangles() - require(rawDangles.size == clonedAuto.elements.size) - // Assign the [[AutoBundle]] fields of the cloned record to the empty [[Dangle]]'s - val dangles = (rawDangles zip clonedAuto.elements).map { case (d, (_, io)) => - d.copy(dataOpt = Some(io)) - } - dangles - } .getOrElse { - // For non-clones, instantiate the child module - val mod = Module(c.module) - mod.dangles - } - } - - // Ask each node in this [[LazyModule]] to call [[BaseNode.instantiate]]. - // This will result in a sequence of [[Dangle]] from these [[BaseNode]]s. - val nodeDangles = wrapper.nodes.reverse.flatMap(_.instantiate()) - // Accumulate all the [[Dangle]]s from this node and any accumulated from its [[wrapper.children]] - val allDangles = nodeDangles ++ childDangles - // Group [[allDangles]] by their [[source]]. - val pairing = SortedMap(allDangles.groupBy(_.source).toSeq: _*) - // For each [[source]] set of [[Dangle]]s of size 2, ensure that these - // can be connected as a source-sink pair (have opposite flipped value). - // Make the connection and mark them as [[done]]. - val done = Set() ++ pairing.values.filter(_.size == 2).map { - case Seq(a, b) => - require(a.flipped != b.flipped) - // @todo <> in chisel3 makes directionless connection. - if (a.flipped) { - a.data <> b.data - } else { - b.data <> a.data - } - a.source - case _ => - None - } - // Find all [[Dangle]]s which are still not connected. These will end up as [[AutoBundle]] [[IO]] ports on the module. - val forward = allDangles.filter(d => !done(d.source)) - // Generate [[AutoBundle]] IO from [[forward]]. - val auto = IO(new AutoBundle(forward.map { d => (d.name, d.data, d.flipped) }: _*)) - // Pass the [[Dangle]]s which remained and were used to generate the [[AutoBundle]] I/O ports up to the [[parent]] [[LazyModule]] - val dangles = (forward zip auto.elements) map { case (d, (_, io)) => - if (d.flipped) { - d.data <> io - } else { - io <> d.data - } - d.copy(dataOpt = Some(io), name = wrapper.suggestedName + "_" + d.name) - } - // Push all [[LazyModule.inModuleBody]] to [[chisel3.internal.Builder]]. - wrapper.inModuleBody.reverse.foreach { - _ () - } - - if (wrapper.shouldBeInlined) { - chisel3.experimental.annotate(new ChiselAnnotation { - def toFirrtl = InlineAnnotation(toNamed) - }) - } - - // Return [[IO]] and [[Dangle]] of this [[LazyModuleImp]]. - (auto, dangles) - } -} - -/** Actual description of a [[Module]] which can be instantiated by a call to [[LazyModule.module]]. - * - * @param wrapper the [[LazyModule]] from which the `.module` call is being made. - */ -class LazyModuleImp(val wrapper: LazyModule) extends Module with LazyModuleImpLike { - /** Instantiate hardware of this `Module`. */ - val (auto, dangles) = instantiate() -} - -/** Actual description of a [[RawModule]] which can be instantiated by a call to [[LazyModule.module]]. - * - * @param wrapper the [[LazyModule]] from which the `.module` call is being made. - */ -class LazyRawModuleImp(val wrapper: LazyModule) extends RawModule with LazyModuleImpLike { - // These wires are the default clock+reset for all LazyModule children. - // It is recommended to drive these even if you manually drive the [[clock]] and [[reset]] of all of the - // [[LazyRawModuleImp]] children. - // Otherwise, anonymous children ([[Monitor]]s for example) will not have their [[clock]] and/or [[reset]] driven properly. - /** drive clock explicitly. */ - val childClock: Clock = Wire(Clock()) - /** drive reset explicitly. */ - val childReset: Reset = Wire(Reset()) - // the default is that these are disabled - childClock := false.B.asClock - childReset := chisel3.DontCare - - def provideImplicitClockToLazyChildren: Boolean = false - val (auto, dangles) = if (provideImplicitClockToLazyChildren) { - withClockAndReset(childClock, childReset) { instantiate() } - } else { - instantiate() - } -} - -/** Used for a [[LazyModule]] which does not need to define any [[LazyModuleImp]] implementation. - * - * It can be used as wrapper that only instantiates and connects [[LazyModule]]s. - */ -class SimpleLazyModule(implicit p: Parameters) extends LazyModule { - lazy val module = new LazyModuleImp(this) -} -class SimpleLazyRawModule(implicit p: Parameters) extends LazyModule { - lazy val module = new LazyRawModuleImp(this) -} - - -/** Allows dynamic creation of [[Module]] hierarchy and "shoving" logic into a [[LazyModule]]. */ -trait LazyScope { - this: LazyModule => - override def toString: String = s"LazyScope named $name" - - /** Evaluate `body` in the current [[LazyModule.scope]] */ - def apply[T](body: => T): T = { - // Preserve the previous value of the [[LazyModule.scope]], because when calling [[apply]] function, - // [[LazyModule.scope]] will be altered. - val saved = LazyModule.scope - // [[LazyModule.scope]] stack push. - LazyModule.scope = Some(this) - // Evaluate [[body]] in the current `scope`, saving the result to [[out]]. - val out = body - // Check that the `scope` after evaluating `body` is the same as when we started. - require(LazyModule.scope.isDefined, s"LazyScope $name tried to exit, but scope was empty!") - require(LazyModule.scope.get eq this, s"LazyScope $name exited before LazyModule ${LazyModule.scope.get.name} was closed") - // [[LazyModule.scope]] stack pop. - LazyModule.scope = saved - out - } -} - -/** Used to automatically create a level of module hierarchy (a [[SimpleLazyModule]]) within which [[LazyModule]]s can be instantiated and connected. - * - * It will instantiate a [[SimpleLazyModule]] to manage evaluation of `body` and evaluate `body` code snippets in this scope. - */ -object LazyScope { - /** Create a [[LazyScope]] with an implicit instance name. - * - * @param body code executed within the generated [[SimpleLazyModule]]. - * @param valName instance name of generated [[SimpleLazyModule]]. - * @param p [[Parameters]] propagated to [[SimpleLazyModule]]. - */ - def apply[T](body: => T)(implicit valName: ValName, p: Parameters): T = { - apply(valName.name, "SimpleLazyModule", None)(body)(p) - } - - /** Create a [[LazyScope]] with an explicitly defined instance name. - * - * @param name instance name of generated [[SimpleLazyModule]]. - * @param body code executed within the generated `SimpleLazyModule` - * @param p [[Parameters]] propagated to [[SimpleLazyModule]]. - */ - def apply[T](name: String)(body: => T)(implicit p: Parameters): T = { - apply(name, "SimpleLazyModule", None)(body)(p) - } - - /** Create a [[LazyScope]] with an explicit instance and class name, and control inlining. - * - * @param name instance name of generated [[SimpleLazyModule]]. - * @param desiredModuleName class name of generated [[SimpleLazyModule]]. - * @param overrideInlining tell FIRRTL that this [[SimpleLazyModule]]'s module should be inlined. - * @param body code executed within the generated `SimpleLazyModule` - * @param p [[Parameters]] propagated to [[SimpleLazyModule]]. - */ - def apply[T]( - name: String, - desiredModuleName: String, - overrideInlining: Option[Boolean] = None) - (body: => T) - (implicit p: Parameters): T = - { - val scope = LazyModule(new SimpleLazyModule with LazyScope { - override lazy val desiredName = desiredModuleName - override def shouldBeInlined = overrideInlining.getOrElse(super.shouldBeInlined) - }).suggestName(name) - scope { - body - } - } - - /** Create a [[LazyScope]] to temporarily group children for some reason, but tell Firrtl to inline it. - * - * For example, we might want to control a set of children's clocks but then not keep the parent wrapper. - * - * @param body code executed within the generated `SimpleLazyModule` - * @param p [[Parameters]] propagated to [[SimpleLazyModule]]. - */ - def inline[T](body: => T)(implicit p: Parameters): T = { - apply("noname", "ShouldBeInlined", Some(false))(body)(p) - } -} - -/** One side metadata of a [[Dangle]]. - * - * Describes one side of an edge going into or out of a [[BaseNode]]. - * - * @param serial the global [[BaseNode.serial]] number of the [[BaseNode]] that this [[HalfEdge]] connects to. - * @param index the `index` in the [[BaseNode]]'s input or output port list that this [[HalfEdge]] belongs to. - */ -case class HalfEdge(serial: Int, index: Int) extends Ordered[HalfEdge] { - - import scala.math.Ordered.orderingToOrdered - - def compare(that: HalfEdge): Int = HalfEdge.unapply(this) compare HalfEdge.unapply(that) -} - -/** [[Dangle]] captures the `IO` information of a [[LazyModule]] and which two [[BaseNode]]s the [[Edges]]/[[Bundle]] connects. - * - * [[Dangle]]s are generated by [[BaseNode.instantiate]] - * using [[MixedNode.danglesOut]] and [[MixedNode.danglesIn]] , - * [[LazyModuleImp.instantiate]] connects those that go to internal or explicit IO connections - * in a [[LazyModule]]. - * - * @param source the source [[HalfEdge]] of this [[Dangle]], which captures the source [[BaseNode]] and the port `index` within that [[BaseNode]]. - * @param sink sink [[HalfEdge]] of this [[Dangle]], which captures the sink [[BaseNode]] and the port `index` within that [[BaseNode]]. - * @param flipped flip or not in [[AutoBundle.makeElements]]. If true this corresponds to `danglesOut`, if false it corresponds to `danglesIn`. - * @param dataOpt actual [[Data]] for the hardware connection. Can be empty if this belongs to a cloned module - */ -case class Dangle(source: HalfEdge, sink: HalfEdge, flipped: Boolean, name: String, dataOpt: Option[Data]) { - def data = dataOpt.get -} - -/** [[AutoBundle]] will construct the [[Bundle]]s for a [[LazyModule]] in [[LazyModuleImpLike.instantiate]], - * - * @param elts is a sequence of data containing for each IO port a tuple of (name, data, flipped), where - * name: IO name - * data: actual data for connection. - * flipped: flip or not in [[makeElements]] - */ -final class AutoBundle(elts: (String, Data, Boolean)*) extends Record { - // We need to preserve the order of elts, despite grouping by name to disambiguate things. - val elements: SeqMap[String, Data] = SeqMap() ++ elts.zipWithIndex.map(makeElements).groupBy(_._1).values.flatMap { - // If name is unique, it will return a Seq[index -> (name -> data)]. - case Seq((key, element, i)) => Seq(i -> (key -> element)) - // If name is not unique, name will append with j, and return `Seq[index -> (s"${name}_${j}" -> data)]`. - case seq => seq.zipWithIndex.map { case ((key, element, i), j) => i -> (key + "_" + j -> element) } - }.toList.sortBy(_._1).map(_._2) - require(elements.size == elts.size) - - // Trim final "(_[0-9]+)*$" in the name, flip data with flipped. - private def makeElements(tuple: ((String, Data, Boolean), Int)) = { - val ((key, data, flip), i) = tuple - // Trim trailing _0_1_2 stuff so that when we append _# we don't create collisions. - val regex = new Regex("(_[0-9]+)*$") - val element = if (flip) Flipped(data.cloneType) else data.cloneType - (regex.replaceAllIn(key, ""), element, i) - } -} - -trait ModuleValue[T] { - def getWrappedValue: T -} - -/** Used to inject code snippets to be evaluated in [[LazyModuleImp.instantiate]] in the current [[LazyModule.scope]]. - * - * It can be used to create additional hardware outside of the [[LazyModule.children]], - * connections other than the internal [[BaseNode]] connections, - * or additional IOs aside from the [[AutoBundle]] - */ -object InModuleBody { - def apply[T](body: => T): ModuleValue[T] = { - require(LazyModule.scope.isDefined, s"InModuleBody invoked outside a LazyModule") - val scope = LazyModule.scope.get - // a wrapper to [[body]], being able to extract result after `execute`. - val out = new ModuleValue[T] { - var result: Option[T] = None - - def execute(): Unit = { - result = Some(body) - } - - def getWrappedValue: T = { - require(result.isDefined, s"InModuleBody contents were requested before module was evaluated!") - result.get - } - } - - // Prepend [[out.execute]] to [[scope.inModuleBody]], - // it is a val with type of `() => Unit`, which will be executed in [[LazyModuleImp.instantiate]]. - scope.inModuleBody = out.execute _ +: scope.inModuleBody - out - } -} diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala deleted file mode 100644 index 51d3b7e92ad..00000000000 --- a/src/main/scala/diplomacy/Nodes.scala +++ /dev/null @@ -1,1800 +0,0 @@ -// See LICENSE.SiFive for license details. - -package freechips.rocketchip.diplomacy - -import chisel3._ -import chisel3.experimental.SourceInfo -import org.chipsalliance.cde.config.{Field, Parameters} -import freechips.rocketchip.util.HeterogeneousBag - -import scala.collection.immutable -import scala.collection.mutable.ListBuffer - -/** A field available in [[Parameters]] used to determine whether [[InwardNodeImp.monitor]] will be called. */ -case object MonitorsEnabled extends Field[Boolean](true) - -/** When rendering the edge in a graphical format, flip the order in which the edges' source and sink are presented. - * - * For example, when rendering graphML, yEd by default tries to put the source node vertically above the sink node, but - * [[RenderFlipped]] inverts this relationship. When a particular [[LazyModule]] contains both source nodes and sink nodes, - * flipping the rendering of one node's edge will usual produce a more concise visual layout for the [[LazyModule]]. - */ -case object RenderFlipped extends Field[Boolean](false) - -/** [[RenderedEdge]] can set the color and label of the visualization of the DAG. */ -case class RenderedEdge( - colour: String, - label: String = "", - flipped: Boolean = false) - -/** [[InwardNodeImp]] defines the types that describe the inward side of the [[BaseNode]]. - * - * @tparam DI The type of the downward-flowing parameters received on the inner side of the node. - * @tparam UI The type of the upward-flowing parameters generated by the inner side of the node. - * @tparam EI The type of the diplomatically-resolved parameters for an Edge connected to the inner side of the node. - * @tparam BI The type of the [[chisel3.Data]] (usually a [[chisel3.Bundle]]) used when connecting to the inner side of the node, - * corresponding to the real hardware interface that is emitted along the graph edge, - * generally parameterized by the [[EI]] type. - */ -trait InwardNodeImp[DI, UI, EI, BI <: Data] -{ - /** Creates the inward edge parameters by combining the downward-flowing and upward-flowing parameters for edges - * that connect to the inward side of this [[BaseNode]]. - * - * It is left up to a user defining a particular protocol implementation to decide how the parameters flowing through - * the graph in both directions on this Edge are combined into a single representation. - * - * @param pd The downward-flowing parameters into the node along the edge. - * @param pu The upward-flowing parameters going out of the node along the edge. - * @param p A view of [[Parameters]] at the point at which the returned edge is being bound. - * @param sourceInfo [[SourceInfo]] of this edge. - * @return An inward edge of this node. - */ - def edgeI(pd: DI, pu: UI, p: Parameters, sourceInfo: SourceInfo): EI - - /** Create an inward bundle parameterized by the inward edge. - * - * @param ei Inward edge of this node. - * @return An outward Bundle of this node parameterized by the negotiated Edge parameters. - */ - def bundleI(ei: EI): BI - - /** Defines how input parameters can be "mixed" or negotiated together. - * - * The default behavior is to just return `pu`. - * - * @param pu The upward-flowing parameters going out of the node along the edge. - * @param node An inward node to "mix" the upward-flowing parameters into. - * @return Altered version of the upward-flowing parameters. - */ - def mixI(pu: UI, node: InwardNode[DI, UI, BI]): UI = pu - - /** Function to generate and attach a monitor for this node input. - * - * @param bundle Inward bundle of this node to attach the monitor to. - * @param edge Edge of this node used to parameterize the bundle. - */ - def monitor(bundle: BI, edge: EI): Unit = {} - - /** Define how the edge should be rendered (e.g. in GraphML). - * - * @param e Edge to render. - * @return [[RenderedEdge]] description of how the edge should be generated. - */ - def render(e: EI): RenderedEdge -} - -/** [[OutwardNodeImp]] defines the types that describe the outwards side of the [[BaseNode]]. - * - * @tparam DO The type of the downward-flowing parameters generated by the outer side of the node - * @tparam UO Tye type of the upward-flowing parameters received by the outer side of the node - * @tparam EO The type of the diplomatically-resolved parameters for an Edge connected to the outer side of the node. - * @tparam BO The type of the [[chisel3.Data]] (usually a [[chisel3.Bundle]]) used when connecting to the outer side of the node, - * corresponding to the real hardware interface that is emitted along the graph edge, - * generally parameterized by the [[EO]] type. - */ -trait OutwardNodeImp[DO, UO, EO, BO <: Data] -{ - /** Creates the outward edge parameters by combining the downward-flowing and upward-flowing parameters for edges - * that connect to the outward side of this [[BaseNode]]. - * - * It is left up to a user defining a particular protocol implementation to decide how the parameters flowing through - * the graph in both directions on this Edge are combined into a single representation. - * - * @param pd The downward-flowing parameters going out of the node along the edge. - * @param pu The upward-flowing parameters into the node along the edge. - * @param p A view of [[Parameters]] at the point at which the returned edge is being bound. - * @param sourceInfo [[SourceInfo]] of this edge. - * @return An outward edge of this node. - */ - def edgeO(pd: DO, pu: UO, p: Parameters, sourceInfo: SourceInfo): EO - - /** Create an outward Bundle parameterized by the outward edge. - * - * @param eo Outward Edge of this node. - * @return An outward Bundle of this node parameterized by the negotiated Edge parameters. - */ - def bundleO(eo: EO): BO - - /** Defines how outward parameters can be "mixed" or negotiated together. - * - * The default behavior is to just return `pd`. - * - * @param pd The downward-flowing parameters into the node along the edge. - * @param node An outward node to "mix" the downward-flowing parameters into. - * @return Altered version of the downward-flowing parameters. - */ - def mixO(pd: DO, node: OutwardNode[DO, UO, BO]): DO = pd -} - -/** The [[NodeImp]] combines an [[InwardNodeImp]] and an [[OutwardNodeImp]]. - * - * This allows it to define whether it is a protocol-modifying (bridging) sort of node, - * or whether it is an adapter type node that just modifies the parameters within a protocol. - * - * This class has no members and is solely used for holding type information. - * Applications of diplomacy should extend [[NodeImp]] with a case object that sets concrete type arguments. - * - * @tparam D Type of the downward-flowing parameters of the node. - * @tparam U Type of upward-flowing parameters of the node. - * @tparam EO Type of the parameters describing an edge on the outer side of the node. - * @tparam EI Type of the parameters describing an edge on the inner side of the node. - * @tparam B Bundle type generated on edges connecting to this node. - */ -abstract class NodeImp[D, U, EO, EI, B <: Data] extends Object - with InwardNodeImp[D, U, EI, B] - with OutwardNodeImp[D, U, EO, B] - -/** A [[NodeImp]] where the inward and outward edge parameters are of the same type. - * - * If, in a given protocol implementation, the parameters visible to the node on the inward side of an edge are - * the same as the parameters visible to the node on the outward side of an edge, - * [[SimpleNodeImp]] can be used instead of [[NodeImp]]. - * - * @tparam D Type of the downward-flowing parameters of the node. - * @tparam U Type of the upward-flowing parameters of the node. - * @tparam E Edge Parameters describing the connections on either side of the node. - * @tparam B Bundle type generated on edges connecting to this node. - */ -abstract class SimpleNodeImp[D, U, E, B <: Data] - extends NodeImp[D, U, E, E, B] { - /** Creates the edge parameters by combining the downward-flowing and upward-flowing parameters for edges that connect to this node. - * - * It is left up to a user defining a particular protocol implementation to decide how the parameters flowing through the graph in - * both directions are combined into a single representation on an Edge. - * - * @param pd The downward-flowing parameters into the node along the edge. - * @param pu The upward-flowing parameters going out of the node along the edge. - * @param p [[Parameters]]s which can be used during negotiation. - * @param sourceInfo [[SourceInfo]] of this edge. - * @return Negotiated edge parameters. - */ - def edge(pd: D, pu: U, p: Parameters, sourceInfo: SourceInfo): E - - def edgeO(pd: D, pu: U, p: Parameters, sourceInfo: SourceInfo): E = edge(pd, pu, p, sourceInfo) - - def edgeI(pd: D, pu: U, p: Parameters, sourceInfo: SourceInfo): E = edge(pd, pu, p, sourceInfo) - - /** Generate the Bundle from the negotiated Edge parameters. - * - * @param e the negotiated Edge parameters - * @return the corresponding Bundle of this node - */ - def bundle(e: E): B - - def bundleO(e: E): B = bundle(e) - - def bundleI(e: E): B = bundle(e) -} - -/** [[BaseNode]] is the abstract base class of the type hierarchy of diplomacy node classes. - * - * @param valName [[ValName]] of this node, used by naming inference. - */ -abstract class BaseNode(implicit val valName: ValName) { - /** All subclasses of [[BaseNode]]s are expected to be instantiated only within [[LazyModule]]s. - * - * Sometimes one wants to view the entire diplomacy graph in a way - * where you do not care about the specific types of the edges. - * [[BaseNode]]s are type-erased and provide this view. - * - * @return The [[LazyModule]] which contains this Node. - */ - val scope: Option[LazyModule] = LazyModule.scope - - /** @return The index for this node in the containing [[LazyModule]]/[[LazyScope]]'s list of [[BaseNode]]s */ - val index: Int = scope.map(_.nodes.size).getOrElse(0) - - /** @return The [[LazyModule]] which contains this [[BaseNode]] */ - def lazyModule: LazyModule = scope.get - - // Prepend this node to the current [[LazyModule]]'s list of nodes - scope.foreach { lm => lm.nodes = this :: lm.nodes } - - /** @return The serial number for this node in the global list of [[BaseNode]]s. */ - val serial: Int = BaseNode.serial - - BaseNode.serial = BaseNode.serial + 1 - - /** Instantiate this node. - * - * This happens after all nodes connections have been made and we are ready to perform parameter negotiation. - * This also determines which connections need to leave this node's LazyScope and cross hierarchical boundaries. - * That information is captured in [[Dangle]]s which are returned from this function. - * - * @return A sequence of [[Dangle]]s from this node that leave this [[BaseNode]]'s [[LazyScope]]. - */ - protected[diplomacy] def instantiate(): Seq[Dangle] - /** Determine the [[Dangle]]'s for connections without instantiating the node, or any child nodes - * - * @return A sequence of [[Dangle]]s from this node that leave this [[BaseNode]]'s [[LazyScope]]. - */ - protected[diplomacy] def cloneDangles(): Seq[Dangle] - - /** @return name of this node. */ - def name: String = scope.map(_.name).getOrElse("TOP") + "." + valName.name - - /** Determines whether or not this node will be excluded from the graph visualization. - * - * By default, if this node has neither inputs nor outputs it will be excluded. - */ - def omitGraphML: Boolean = outputs.isEmpty && inputs.isEmpty - - /** Debug string of this node, used in [[LazyModule.graphML]]. */ - lazy val nodedebugstring: String = "" - - /** Mark whether this node represents a circuit "identity" that outputs its inputs unchanged. - * - * This information may be used to elide monitors or inline the parent module. - */ - def circuitIdentity: Boolean = false - - /** @return A sequence of [[LazyModule]] up to and including Top. */ - def parents: Seq[LazyModule] = scope.map(lm => lm +: lm.parents).getOrElse(Nil) - - /** @return The context string for debug. */ - def context: String = { - s"""$description $name node: - |parents: ${parents.map(_.name).mkString("/")} - |locator: ${scope.map(_.line).getOrElse("")} - |""".stripMargin - } - - /** Determines the name to be used in elements of auto-punched bundles. - * - * It takes the name of the node as determined from [[valName]], - * converts camel case into snake case, and strips "Node" or "NodeOpt" suffixes. - */ - def wirePrefix: String = { - val camelCase = "([a-z])([A-Z])".r - val decamel = camelCase.replaceAllIn(valName.name, _ match { case camelCase(l, h) => l + "_" + h }) - val name = decamel.toLowerCase.stripSuffix("_opt").stripSuffix("node").stripSuffix("_") - if (name.isEmpty) "" else name + "_" - } - - /** @return [[BaseNode]] description, which should be defined by subclasses and is generally expected to be a constant. */ - def description: String - - /** @return [[BaseNode]] instance description, which can be overridden with more detailed information about each node. */ - def formatNode: String = "" - - /** @return Metadata to visualize inward edges into this node. */ - def inputs: Seq[(BaseNode, RenderedEdge)] - - /** @return Metadata to visualize outward edges from this node. */ - def outputs: Seq[(BaseNode, RenderedEdge)] - - /** @return Whether this node can handle [[BIND_FLEX]] type connections on either side. - * - * For example, a node `b` will have [[flexibleArityDirection]] be `true` if both are legal: - * `a :*=* b :*= c`, which resolves to `a :*= b :*= c` - * or - * `a :=* b :*=* c`, which resolves to `a :=* b :=* c` - * - * If this is `false`, the node can only support `:*=*` if it connects to a node with `flexibleArityDirection = true` - */ - protected[diplomacy] def flexibleArityDirection: Boolean = false - - /** @return The sink cardinality. - * - * How many times is this node used as a sink. - */ - protected[diplomacy] val sinkCard: Int - - /** @return The source cardinality. - * - * How many times is this node used as a source. - */ - protected[diplomacy] val sourceCard: Int - - /** @return The "flex" cardinality. - * - * How many times is this node used in a way that could be either source or sink, depending on final - * directional determination. - */ - protected[diplomacy] val flexes: Seq[BaseNode] - - /** Resolves the flex to be either source or sink. - * - * @return A value >= 0 if it is sink cardinality, a negative value for source cardinality. The magnitude of the value does not matter. - */ - protected[diplomacy] val flexOffset: Int -} - -/** Companion object for [[BaseNode]], which is only used to hold the the global serial number of all [[BaseNode]]s. */ -object BaseNode { - protected[diplomacy] var serial = 0 -} - -/** Trait that enables a string representation of an edge. */ -trait FormatEdge { - def formatEdge: String -} - -/** Trait that enables iterating over a [[BaseNode]]'s edges to produce a formatted string representation. - * - * In practice this is generally GraphML metadata. - */ -trait FormatNode[I <: FormatEdge, O <: FormatEdge] extends BaseNode { - def edges: Edges[I,O] - - /** Format the edges of the [[BaseNode]] for emission (generally in GraphML). */ - override def formatNode = if (circuitIdentity) "" else { - edges.out.map(currEdge => - "On Output Edge:\n\n" + currEdge.formatEdge).mkString + - "\n---------------------------------------------\n\n" + - edges.in.map(currEdge => - "On Input Edge:\n\n" + currEdge.formatEdge).mkString - } -} - -/** A Handle with no explicitly defined binding functionality. - * - * A [[NoHandle]] is at the top of the Handle type hierarchy, but it does not define any binding operators, - * so by itself a [[NoHandle]] cannot be used on either side of a bind operator. - * - * For example, a source node connected directly to a sink node produces a [[NoHandle]], - * because there are no further bindings that could be applied to either side of the pair of nodes. - * - * The other Handle types extend this type and bestow actual binding semantics. - * They can always be used wherever a [[NoHandle]] is expected because a [[NoHandle]] - * doesn't provide any guaranteed behavior. - * - * Handle algebra: - * - * "x---x" [[NoHandle]] - * "x---<" [[InwardNodeHandle]] - * "<---x" [[OutwardNodeHandle]] - * "<---<" (Full) [[NodeHandle]] - * - * "<" can be bound to (arrow points in the direction of binding). - * "x" cannot be bound to. - * - * The left side is outer, the right side is inner. - * - * Two Handles can be bound if their adjacent ends are both "<". - */ -trait NoHandle -case object NoHandleObject extends NoHandle - -/** A Handle that can be used on either side of a bind operator. */ -trait NodeHandle[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] - extends InwardNodeHandle[DI, UI, EI, BI] with OutwardNodeHandle[DO, UO, EO, BO] { - /** Connects two full nodes handles => full node handle. - * - * <---< := <---< == <---< - * This and that node are both [[BIND_ONCE]]. - * - * @param h A source node also with sink handle. - * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`. - */ - override def := [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, EX, BX, DO, UO, EO, BO] = { bind(h, BIND_ONCE); NodeHandle(h, this) } - - /** Connects two full nodes handles => full node handle. - * - * <---< :*= <---< == <---< - * [[BIND_STAR]] this node as sink, [[BIND_QUERY]] that node as source. - * - * @param h A source node also with sink handle. - * @return A [[NodeHandle]] with that node as `InwardNode`, this node as `OutwardNode`. - */ - override def :*= [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, EX, BX, DO, UO, EO, BO] = { bind(h, BIND_STAR); NodeHandle(h, this) } - - /** Connects two full nodes handles => full node handle. - * - * <---< :=* <---< == <---< - * [[BIND_QUERY]] this node as sink, [[BIND_STAR]] that node as source. - * - * @param h A source node also with sink handle. - * @return A [[NodeHandle]] with that node as `InwardNode`, this node as `OutwardNode`. - */ - override def :=* [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, EX, BX, DO, UO, EO, BO] = { bind(h, BIND_QUERY); NodeHandle(h, this) } - - /** Connects two full nodes handles => full node handle. - * - * <---< :*=* <---< == <---< - * [[BIND_FLEX]] this node as sink, [[BIND_FLEX]] that node as source. - * - * @param h A source node also with sink handle. - * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`. - */ - override def :*=*[DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, EX, BX, DO, UO, EO, BO] = { bind(h, BIND_FLEX); NodeHandle(h, this) } - - /** Connects a full node with an output node => an output handle. - * - * <---< := <---x == <---x - * [[BIND_ONCE]] this node as sink, [[BIND_ONCE]] that node as source. - * - * @param h A source node also without sink handle. - * @return A [[OutwardNodeHandle]] with this node as `outwardNode`. - */ - override def := [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_ONCE); this } - - /** Connects a full node with an output node => an output handle. - * - * <---< :*= <---x == <---x - * [[BIND_STAR]] this node as sink, [[BIND_QUERY]] that node as source. - * - * @param h A source node also without sink handle. - * @return A [[OutwardNodeHandle]] with this node as `outwardNode`. - */ - override def :*= [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_STAR); this } - - /** Connects a full node with an output => an output. - * - * <---< :=* <---x == <---x - * [[BIND_QUERY]] this node as sink, [[BIND_STAR]] that node as source. - * - * @param h A source node also without sink handle. - * @return A [[OutwardNodeHandle]] with this node as `outwardNode`. - */ - override def :=* [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_QUERY); this } - - /** Connects a full node with an output => an output. - * - * <---< :*=* <---x == <---x - * [[BIND_FLEX]] this node as sink, [[BIND_FLEX]] that node as source. - * - * @param h A source node also without sink handle. - * @return A [[OutwardNodeHandle]] with this node as `outwardNode`. - */ - override def :*=*[EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_FLEX); this } -} - -object NodeHandle { - /** generate a [[NodeHandle]] by combining an [[InwardNodeHandle]] and an [[OutwardNodeHandle]]. - * - * @param i Inward node handle. - * @param o Outward node handle. - * @return [[NodeHandlePair]] with `inwardNode` of `i`, `outwardNode` of `o`. - */ - def apply[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](i: InwardNodeHandle[DI, UI, EI, BI], o: OutwardNodeHandle[DO, UO, EO, BO]) = new NodeHandlePair(i, o) -} - -/** A data structure that preserves information about the innermost and outermost Nodes in a [[NodeHandle]]. */ -class NodeHandlePair[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] - (inwardHandle: InwardNodeHandle[DI, UI, EI, BI], outwardHandle: OutwardNodeHandle[DO, UO, EO, BO]) - extends NodeHandle[DI, UI, EI, BI, DO, UO, EO, BO] { - /** @return [[InwardNode]] of [[inwardHandle]]. */ - val inward: InwardNode[DI, UI, BI] = inwardHandle.inward - - /** @return [[OutwardNode]] of [[outwardHandle]]. */ - val outward: OutwardNode[DO, UO, BO] = outwardHandle.outward - - /** @return The innermost [[InwardNodeImp]] of this [[NodeHandlePair]]. */ - def inner: InwardNodeImp[DI, UI, EI, BI] = inwardHandle.inner - - /** @return The outermost [[OutwardNodeImp]] of [[NodeHandlePair]]. */ - def outer: OutwardNodeImp[DO, UO, EO, BO] = outwardHandle.outer -} - -/** A handle for an [[InwardNode]], which may appear on the left side of a bind operator. */ -trait InwardNodeHandle[DI, UI, EI, BI <: Data] extends NoHandle -{ - /** @return [[InwardNode]] of `inwardHandle`. */ - def inward: InwardNode[DI, UI, BI] - - /** @return [[InwardNodeImp]] of `inwardHandle`. */ - def inner: InwardNodeImp[DI, UI, EI, BI] - - /** Bind this node to an [[OutwardNodeHandle]]. */ - protected def bind[EY](h: OutwardNodeHandle[DI, UI, EY, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = inward.bind(h.outward, binding) - - /** Connect an input node with a full node => inward node handle. - * - * x---< := <---< == x---< - * [[BIND_ONCE]] this node as sink, [[BIND_ONCE]] that node as source. - * - * @param h A source node also with sink handle. - * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`. - */ - def := [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, EX, BX] = { bind(h, BIND_ONCE); h } - - /** Connect an input node with a full node => an input node. - * - * x---< :*= <---< == x---< - * [[BIND_STAR]] this node as sink, [[BIND_QUERY]] that node as source. - * - * @param h A Source node also with sink handle. - * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`. - */ - def :*= [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, EX, BX] = { bind(h, BIND_STAR); h } - - /** Connect an input node with a full node => an inward node handle. - * - * x---< :=* <---< == x---< - * [[BIND_QUERY]] this node as sink, [[BIND_STAR]] that node as source. - * - * @param h A source node also with sink handle. - * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`. - */ - def :=* [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, EX, BX] = { bind(h, BIND_QUERY); h } - - /** Connect an input node with a full node => an input node. - * - * x---< :*=* <---< == x---< - * [[BIND_FLEX]] this node as sink, [[BIND_FLEX]] that node as source. - * - * @param h A source node also with sink handle. - * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`. - */ - def :*=*[DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, EX, BX] = { bind(h, BIND_FLEX); h } - - /** Connect an input node with output node => no node. - * - * x---< := <---x == x---x - * [[BIND_ONCE]] this node as sink, [[BIND_ONCE]] that node as source. - * - * @param h A source node also without sink handle. - * @return A [[NoHandle]] since neither side can bind to a node. - */ - def := [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_ONCE); NoHandleObject } - - /** Connect an input node with output node => no node. - * - * x---< :*= <---x == x---x - * [[BIND_STAR]] this node as sink, [[BIND_QUERY]] that node as source. - * - * @param h A source node also without sink handle. - * @return A [[NoHandle]] since neither side can bind to a node. - */ - def :*= [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_STAR); NoHandleObject } - - /** Connect an input node with output node => no node. - * - * x---< :=* <---x == x---x - * [[BIND_QUERY]] this node as sink, [[BIND_STAR]] that node as source. - * - * @param h A source node also without sink handle. - * @return A [[NoHandle]] since neither side can bind to another node. - */ - def :=* [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_QUERY); NoHandleObject } - - /** Connect an input node with output node => no node. - * - * x---< :*=* <---x == x---x - * [[BIND_FLEX]] this node as sink, [[BIND_FLEX]] that node as source. - * - * @param h A source node also without sink handle. - * @return A [[NoHandle]] since neither side can bind to another node. - */ - def :*=*[EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_FLEX); NoHandleObject } -} - -/** Enumeration of types of binding operations. */ -sealed trait NodeBinding - -/** Only connects a single edge. */ -case object BIND_ONCE extends NodeBinding { - override def toString: String = "once" -} - -/** Connects N (N >= 0) edges. - * - * The other side of the edge determines cardinality. - */ -case object BIND_QUERY extends NodeBinding { - override def toString: String = "query" -} - -/** Connect N (N >= 0) edges. - * - * Our side of the edge determines cardinality. - */ -case object BIND_STAR extends NodeBinding { - override def toString: String = "star" -} - -/** Connect N (N >= 0) connections. - * - * The number of edges N will be determined by either the right or left side, - * once the direction ([[BIND_STAR]] or [[BIND_QUERY]]) is determined by the other connections as well. - */ -case object BIND_FLEX extends NodeBinding { - override def toString: String = "flex" -} - -/** A Node that defines inward behavior, meaning that it can have edges coming into it and be used on the left side of binding expressions. */ -trait InwardNode[DI, UI, BI <: Data] extends BaseNode { - /** accumulates input connections. */ - private val accPI = ListBuffer[(Int, OutwardNode[DI, UI, BI], NodeBinding, Parameters, SourceInfo)]() - - /** Initially `false`, set to `true` once [[iBindings]] has been evaluated. */ - private var iRealized = false - - /** @return debug information of [[iBindings]]. */ - def iBindingInfo: String = s"""${iBindings.size} inward nodes bound: [${iBindings.map(n => s"${n._3}-${n._2.name}").mkString(",")}]""" - - - /** The accumulated number of input connections. */ - protected[diplomacy] def iPushed: Int = accPI.size - - /** Accumulate an input connection. - * - * Can only be called before [[iBindings]] is accessed. - * - * @param index index of this [[InwardNode]] in that [[OutwardNode]]. - * @param node the [[OutwardNode]] to bind to this [[InwardNode]]. - * @param binding [[NodeBinding]] type. - */ - protected[diplomacy] def iPush(index: Int, node: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = { - val info = sourceLine(sourceInfo, " at ", "") - require (!iRealized, - s"""Diplomacy has detected a problem in your code: - |The following node was incorrectly connected as a sink to ${node.name} after its .module was evaluated at $info. - |$context - |$iBindingInfo - |""".stripMargin) - accPI += ((index, node, binding, p, sourceInfo)) - } - - /** Ends the binding accumulation stage and returns all the input bindings to this node. - * - * Evaluating this lazy val will mark the inwards bindings as frozen, - * preventing subsequent bindings from being created via [[iPush]]. - * - * The bindings are each a tuple of: - * - numeric index of this binding in the other end of [[OutwardNode]]. - * - [[OutwardNode]] on the other end of this binding. - * - [[NodeBinding]] describing the type of binding. - * - A view of [[Parameters]] where the binding occurred. - * - [[SourceInfo]] for source-level error reporting. - */ - protected[diplomacy] lazy val iBindings: immutable.Seq[(Int, OutwardNode[DI, UI, BI], NodeBinding, Parameters, SourceInfo)] = { iRealized = true; accPI.result() } - - /** resolved [[BIND_STAR]] binding of inward nodes: how many connections the star represents. */ - protected[diplomacy] val iStar: Int - - /** A mapping to convert Node binding index to port range. - * - * @return a sequence of tuple of mapping, the item in each a tuple of: - * - index: the index of connected [[OutwardNode]] - * - element: port range of connected [[OutwardNode]] - */ - protected[diplomacy] val iPortMapping: Seq[(Int, Int)] - - /** "Forward" an input connection through this node so that the node can be removed from the graph. - * - * @return None if no forwarding is needing. - */ - protected[diplomacy] def iForward(x: Int): Option[(Int, InwardNode[DI, UI, BI])] = None - - /** Downward-flowing inward parameters. - * - * Generated from the nodes connected to the inward side of this node and sent downstream to this node. - */ - protected[diplomacy] val diParams: Seq[DI] - - /** Upward-flowing inward parameters. - * - * Generated by this node and sent upstream to the nodes connected to the inward side of this node. - */ - protected[diplomacy] val uiParams: Seq[UI] - - /** Create a binding from this node to an [[OutwardNode]]. - * - * @param h The [[OutwardNode]] to bind to. - * @param binding [[NodeBinding]] the type of binding. - */ - protected[diplomacy] def bind(h: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit -} - -/** A Handle for OutwardNodes, which may appear on the right side of a bind operator. */ -trait OutwardNodeHandle[DO, UO, EO, BO <: Data] extends NoHandle { - /** @return [[OutwardNode]] of `outwardHandle`. */ - def outward: OutwardNode[DO, UO, BO] - - /** @return [[OutwardNodeImp]] of `inwardHandle`. */ - def outer: OutwardNodeImp[DO, UO, EO, BO] -} - -/** A Node that defines outward behavior, meaning that it can have edges coming out of it. */ -trait OutwardNode[DO, UO, BO <: Data] extends BaseNode { - /** Accumulates output connections. */ - private val accPO = ListBuffer[(Int, InwardNode [DO, UO, BO], NodeBinding, Parameters, SourceInfo)]() - - /** Initially set to `true`, this is set to false once [[oBindings]] is referenced. */ - private var oRealized = false - - /** @return debug information of [[oBindings]]. */ - def oBindingInfo: String = s"""${oBindings.size} outward nodes bound: [${oBindings.map(n => s"${n._3}-${n._2.name}").mkString(",")}]""" - - /** The accumulated number of output connections of this node. */ - protected[diplomacy] def oPushed: Int = accPO.size - - /** Accumulate an output connection. - * - * Can only be called before [[oBindings]] is accessed. - * - * @param index Index of this [[OutwardNode]] in that [[InwardNode]]. - * @param node [[InwardNode]] to bind to. - * @param binding Binding type. - */ - protected[diplomacy] def oPush(index: Int, node: InwardNode [DO, UO, BO], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = { - val info = sourceLine(sourceInfo, " at ", "") - require (!oRealized, - s"""Diplomacy has detected a problem in your code: - |The following node was incorrectly connected as a source to ${node.name} after its .module was evaluated at $info. - |$context - |$oBindingInfo - |""".stripMargin) - accPO += ((index, node, binding, p, sourceInfo)) - } - - /** Ends the binding accumulation stage and returns all the output bindings to this node. - * - * Evaluating this lazy val will mark the outward bindings as frozen, - * preventing subsequent bindings from being created via [[oPush]]. - * - * The bindings are each a tuple of: - * - numeric index of this binding in the other end of [[InwardNode]]. - * - [[InwardNode]] on the other end of this binding - * - [[NodeBinding]] describing the type of binding - * - A view of [[Parameters]] where the binding occurred. - * - [[SourceInfo]] for source-level error reporting - */ - protected[diplomacy] lazy val oBindings: Seq[(Int, InwardNode[DO, UO, BO], NodeBinding, Parameters, SourceInfo)] = { oRealized = true; accPO.result() } - - /** resolved [[BIND_STAR]] binding of outward nodes: how many connections the star represents. */ - protected[diplomacy] val oStar: Int - - /** A mapping to convert Node binding index to port range. - * - * @return a sequence of tuple of mapping, the item in each a tuple of: - * - index: the index of connected [[InwardNode]] - * - element: port range of connected [[InwardNode]] - */ - protected[diplomacy] val oPortMapping: Seq[(Int, Int)] - - /** "Forward" an output connection through this node so that the node can be removed from the graph. - * - * @return None if no forwarding is needed. - */ - protected[diplomacy] def oForward(x: Int): Option[(Int, OutwardNode[DO, UO, BO])] = None - - /** Upward-flowing outward parameters. - * - * Generated from the nodes connected to the outward side of this node and sent upstream to this node. - */ - protected[diplomacy] val uoParams: Seq[UO] - - /** Downward-flowing outward parameters. - * - * Generated by this node and sent downstream to the nodes connected to the outward side of this node. - */ - protected[diplomacy] val doParams: Seq[DO] -} - -abstract class CycleException(kind: String, loop: Seq[String]) extends Exception(s"Diplomatic $kind cycle detected involving $loop") -case class StarCycleException(loop: Seq[String] = Nil) extends CycleException("star", loop) -case class DownwardCycleException(loop: Seq[String] = Nil) extends CycleException("downward", loop) -case class UpwardCycleException(loop: Seq[String] = Nil) extends CycleException("upward", loop) - -/** [[Edges]] is a collection of parameters describing the functionality and connection for an interface, - * which is often derived from the interconnection protocol and can inform the parameterization - * of the hardware bundles that actually implement the protocol. - */ -case class Edges[EI, EO](in: Seq[EI], out: Seq[EO]) - -/** The sealed node class in the package, all node are derived from it. - * - * @param inner Sink interface implementation. - * @param outer Source interface implementation. - * @param valName val name of this node. - * @tparam DI Downward-flowing parameters received on the inner side of the node. - * It is usually a brunch of parameters describing the protocol parameters from a source. - * For an [[InwardNode]], it is determined by the connected [[OutwardNode]]. - * Since it can be connected to multiple sources, this parameter is always a Seq of source port parameters. - * @tparam UI Upward-flowing parameters generated by the inner side of the node. - * It is usually a brunch of parameters describing the protocol parameters of a sink. - * For an [[InwardNode]], it is determined itself. - * @tparam EI Edge Parameters describing a connection on the inner side of the node. - * It is usually a brunch of transfers specified for a sink according to protocol. - * @tparam BI Bundle type used when connecting to the inner side of the node. - * It is a hardware interface of this sink interface. - * It should extends from [[chisel3.Data]], which represents the real hardware. - * @tparam DO Downward-flowing parameters generated on the outer side of the node. - * It is usually a brunch of parameters describing the protocol parameters of a source. - * For an [[OutwardNode]], it is determined itself. - * @tparam UO Upward-flowing parameters received by the outer side of the node. - * It is usually a brunch of parameters describing the protocol parameters from a sink. - * For an [[OutwardNode]], it is determined by the connected [[InwardNode]]. - * Since it can be connected to multiple sinks, this parameter is always a Seq of sink port parameters. - * @tparam EO Edge Parameters describing a connection on the outer side of the node. - * It is usually a brunch of transfers specified for a source according to protocol. - * @tparam BO Bundle type used when connecting to the outer side of the node. - * It is a hardware interface of this source interface. - * It should extends from [[chisel3.Data]], which represents the real hardware. - * - * @note Call Graph of [[MixedNode]] - * - line `─`: source is process by a function and generate pass to others - * - Arrow `→`: target of arrow is generated by source - * - * {{{ - * (from the other node) - * ┌─────────────────────────────────────────────────────────[[InwardNode.uiParams]]─────────────┐ - * ↓ │ - * (binding node when elaboration) [[OutwardNode.uoParams]]────────────────────────[[MixedNode.mapParamsU]]→──────────┐ │ - * [[InwardNode.accPI]] │ │ │ - * │ │ (based on protocol) │ - * │ │ [[MixedNode.inner.edgeI]] │ - * │ │ ↓ │ - * ↓ │ │ │ - * (immobilize after elaboration) (inward port from [[OutwardNode]]) │ ↓ │ - * [[InwardNode.iBindings]]──┐ [[MixedNode.iDirectPorts]]────────────────────→[[MixedNode.iPorts]] [[InwardNode.uiParams]] │ - * │ │ ↑ │ │ │ - * │ │ │ [[OutwardNode.doParams]] │ │ - * │ │ │ (from the other node) │ │ - * │ │ │ │ │ │ - * │ │ │ │ │ │ - * │ │ │ └────────┬──────────────┤ │ - * │ │ │ │ │ │ - * │ │ │ │ (based on protocol) │ - * │ │ │ │ [[MixedNode.inner.edgeI]] │ - * │ │ │ │ │ │ - * │ │ (from the other node) │ ↓ │ - * │ └───[[OutwardNode.oPortMapping]] [[OutwardNode.oStar]] │ [[MixedNode.edgesIn]]───┐ │ - * │ ↑ ↑ │ │ ↓ │ - * │ │ │ │ │ [[MixedNode.in]] │ - * │ │ │ │ ↓ ↑ │ - * │ (solve star connection) │ │ │ [[MixedNode.bundleIn]]──┘ │ - * ├───[[MixedNode.resolveStar]]→─┼─────────────────────────────┤ └────────────────────────────────────┐ │ - * │ │ │ [[MixedNode.bundleOut]]─┐ │ │ - * │ │ │ ↑ ↓ │ │ - * │ │ │ │ [[MixedNode.out]] │ │ - * │ ↓ ↓ │ ↑ │ │ - * │ ┌─────[[InwardNode.iPortMapping]] [[InwardNode.iStar]] [[MixedNode.edgesOut]]──┘ │ │ - * │ │ (from the other node) ↑ │ │ - * │ │ │ │ │ │ - * │ │ │ [[MixedNode.outer.edgeO]] │ │ - * │ │ │ (based on protocol) │ │ - * │ │ │ │ │ │ - * │ │ │ ┌────────────────────────────────────────┤ │ │ - * │ │ │ │ │ │ │ - * │ │ │ │ │ │ │ - * │ │ │ │ │ │ │ - * (immobilize after elaboration)│ ↓ │ │ │ │ - * [[OutwardNode.oBindings]]─┘ [[MixedNode.oDirectPorts]]───→[[MixedNode.oPorts]] [[OutwardNode.doParams]] │ │ - * ↑ (inward port from [[OutwardNode]]) │ │ │ │ - * │ ┌─────────────────────────────────────────┤ │ │ │ - * │ │ │ │ │ │ - * │ │ │ │ │ │ - * [[OutwardNode.accPO]] │ ↓ │ │ │ - * (binding node when elaboration) │ [[InwardNode.diParams]]─────→[[MixedNode.mapParamsD]]────────────────────────────┘ │ │ - * │ ↑ │ │ - * │ └──────────────────────────────────────────────────────────────────────────────────────────┘ │ - * └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - * }}} - */ -sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( - val inner: InwardNodeImp [DI, UI, EI, BI], - val outer: OutwardNodeImp[DO, UO, EO, BO])( - implicit valName: ValName) - extends BaseNode with NodeHandle[DI, UI, EI, BI, DO, UO, EO, BO] with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO] { - // Generate a [[NodeHandle]] with inward and outward node are both this node. - val inward = this - val outward = this - - /** Debug info of nodes binding. */ - def bindingInfo: String = - s"""$iBindingInfo - |$oBindingInfo - |""".stripMargin - - /** Debug info of ports connecting. */ - def connectedPortsInfo: String = - s"""${oPorts.size} outward ports connected: [${oPorts.map(_._2.name).mkString(",")}] - |${iPorts.size} inward ports connected: [${iPorts.map(_._2.name).mkString(",")}] - |""".stripMargin - - /** Debug info of parameters propagations. */ - def parametersInfo: String = - s"""${doParams.size} downstream outward parameters: [${doParams.mkString(",")}] - |${uoParams.size} upstream outward parameters: [${uoParams.mkString(",")}] - |${diParams.size} downstream inward parameters: [${diParams.mkString(",")}] - |${uiParams.size} upstream inward parameters: [${uiParams.mkString(",")}] - |""".stripMargin - - /** For a given node, converts [[OutwardNode.accPO]] and [[InwardNode.accPI]] to [[MixedNode.oPortMapping]] and [[MixedNode.iPortMapping]]. - * - * Given counts of known inward and outward binding and inward and outward star bindings, return the resolved inward stars and outward stars. - * - * This method will also validate the arguments and throw a runtime error if the values are unsuitable for this type of node. - * - * @param iKnown Number of known-size ([[BIND_ONCE]]) input bindings. - * @param oKnown Number of known-size ([[BIND_ONCE]]) output bindings. - * @param iStar Number of unknown size ([[BIND_STAR]]) input bindings. - * @param oStar Number of unknown size ([[BIND_STAR]]) output bindings. - * @return A Tuple of the resolved number of input and output connections. - */ - protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStar: Int, oStar: Int): (Int, Int) - - /** Function to generate downward-flowing outward params from the downward-flowing input params and the current output ports. - * - * @param n The size of the output sequence to generate. - * @param p Sequence of downward-flowing input parameters of this node. - * @return A `n`-sized sequence of downward-flowing output edge parameters. - */ - protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] - - /** Function to generate upward-flowing input parameters from the upward-flowing output parameters [[uiParams]]. - * - * @param n Size of the output sequence. - * @param p Upward-flowing output edge parameters. - * @return A n-sized sequence of upward-flowing input edge parameters. - */ - protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] - - /** @return The sink cardinality of the node, the number of outputs bound with [[BIND_QUERY]] summed with inputs bound with [[BIND_STAR]]. */ - protected[diplomacy] lazy val sinkCard: Int = oBindings.count(_._3 == BIND_QUERY) + iBindings.count(_._3 == BIND_STAR) - - /** @return The source cardinality of this node, the number of inputs bound with [[BIND_QUERY]] summed with the number of output bindings bound with [[BIND_STAR]]. */ - protected[diplomacy] lazy val sourceCard: Int = iBindings.count(_._3 == BIND_QUERY) + oBindings.count(_._3 == BIND_STAR) - - /** @return list of nodes involved in flex bindings with this node. */ - protected[diplomacy] lazy val flexes: Seq[BaseNode] = oBindings.filter(_._3 == BIND_FLEX).map(_._2) ++ iBindings.filter(_._3 == BIND_FLEX).map(_._2) - - /** Resolves the flex to be either source or sink and returns the offset where the [[BIND_STAR]] operators begin greedily taking up the remaining connections. - * - * @return A value >= 0 if it is sink cardinality, a negative value for source cardinality. The magnitude of the return value is not relevant. - */ - protected[diplomacy] lazy val flexOffset: Int = { - /** Recursively performs a depth-first search of the [[flexes]], - * [[BaseNode]]s connected to this node with flex operators. - * The algorithm bottoms out when we either get to a node we have already visited - * or when we get to a connection that is not a flex and can set the direction for us. - * Otherwise, recurse by visiting the `flexes` of each node in the current set - * and decide whether they should be added to the set or not. - * - * @return the mapping of [[BaseNode]] indexed by their serial numbers. - */ - def DFS(v: BaseNode, visited: Map[Int, BaseNode]): Map[Int, BaseNode] = { - if (visited.contains(v.serial) || !v.flexibleArityDirection) { - visited - } else { - v.flexes.foldLeft(visited + (v.serial -> v))((sum, n) => DFS(n, sum)) - } - } - - /** Determine which [[BaseNode]] are involved in resolving the flex connections to/from this node. - * - * @example - * {{{ - * a :*=* b :*=* c - * d :*=* b - * e :*=* f - * }}} - * - * `flexSet` for `a`, `b`, `c`, or `d` will be `Set(a, b, c, d)` - * `flexSet` for `e` or `f` will be `Set(e,f)` - */ - val flexSet = DFS(this, Map()).values - - /** The total number of :*= operators where we're on the left. */ - val allSink = flexSet.map(_.sinkCard).sum - - /** The total number of :=* operators used when we're on the right. */ - val allSource = flexSet.map(_.sourceCard).sum - - require (allSink == 0 || allSource == 0, - s"The nodes ${flexSet.map(_.name)} which are inter-connected by :*=* have ${allSink} :*= operators and ${allSource} :=* operators connected to them, making it impossible to determine cardinality inference direction.") - allSink - allSource - } - - /** @return A value >= 0 if it is sink cardinality, a negative value for source cardinality. */ - protected[diplomacy] def edgeArityDirection(n: BaseNode): Int = { - if ( flexibleArityDirection) flexOffset else - if (n.flexibleArityDirection) n.flexOffset else - 0 - } - - /** For a node which is connected between two nodes, select the one that will influence the direction of the flex resolution. */ - protected[diplomacy] def edgeAritySelect(n: BaseNode, l: => Int, r: => Int): Int = { - val dir = edgeArityDirection(n) - if (dir < 0) l else if (dir > 0) r else 1 - } - - /** Ensure that the same node is not visited twice in resolving `:*=`, etc operators. */ - private var starCycleGuard = false - - /** Resolve all the star operators into concrete indicies. - * As connections are being made, some may be "star" connections which need to be resolved. - * In some way to determine how many actual edges they correspond to. - * We also need to build up the ranges of edges which correspond to each binding operator, so that - * We can apply the correct edge parameters and later build up correct bundle connections. - * - * [[oPortMapping]]: `Seq[(Int, Int)]` where each item is the range of edges corresponding to that oPort (binding operator). - * [[iPortMapping]]: `Seq[(Int, Int)]` where each item is the range of edges corresponding to that iPort (binding operator). - * [[oStar]]: `Int` the value to return for this node `N` for any `N :*= foo` or `N :*=* foo :*= bar` - * [[iStar]]: `Int` the value to return for this node `N` for any `foo :=* N` or `bar :=* foo :*=* N` - */ - protected[diplomacy] lazy val (oPortMapping: Seq[(Int, Int)], iPortMapping: Seq[(Int, Int)], oStar: Int, iStar: Int) = { - try { - if (starCycleGuard) throw StarCycleException() - starCycleGuard = true - // For a given node N... - // Number of foo :=* N - // + Number of bar :=* foo :*=* N - val oStars = oBindings.count { case (_,n,b,_,_) => b == BIND_STAR || (b == BIND_FLEX && edgeArityDirection(n) < 0) } - // Number of N :*= foo - // + Number of N :*=* foo :*= bar - val iStars = iBindings.count { case (_,n,b,_,_) => b == BIND_STAR || (b == BIND_FLEX && edgeArityDirection(n) > 0) } - // 1 for foo := N - // + bar.iStar for bar :*= foo :*=* N - // + foo.iStar for foo :*= N - // + 0 for foo :=* N - val oKnown = oBindings.map { case (_, n, b, _, _) => b match { - case BIND_ONCE => 1 - case BIND_FLEX => edgeAritySelect(n, 0, n.iStar) - case BIND_QUERY => n.iStar - case BIND_STAR => 0 }}.sum - // 1 for N := foo - // + bar.oStar for N :*=* foo :=* bar - // + foo.oStar for N :=* foo - // + 0 for N :*= foo - val iKnown = iBindings.map { case (_, n, b, _, _) => b match { - case BIND_ONCE => 1 - case BIND_FLEX => edgeAritySelect(n, n.oStar, 0) - case BIND_QUERY => n.oStar - case BIND_STAR => 0 }}.sum - // Resolve star depends on the node subclass to implement the algorithm for this. - val (iStar, oStar) = resolveStar(iKnown, oKnown, iStars, oStars) - // Cumulative list of resolved outward binding range starting points - val oSum = oBindings.map { case (_, n, b, _, _) => b match { - case BIND_ONCE => 1 - case BIND_FLEX => edgeAritySelect(n, oStar, n.iStar) - case BIND_QUERY => n.iStar - case BIND_STAR => oStar }}.scanLeft(0)(_+_) - // Cumulative list of resolved inward binding range starting points - val iSum = iBindings.map { case (_, n, b, _, _) => b match { - case BIND_ONCE => 1 - case BIND_FLEX => edgeAritySelect(n, n.oStar, iStar) - case BIND_QUERY => n.oStar - case BIND_STAR => iStar }}.scanLeft(0)(_+_) - // Create ranges for each binding based on the running sums and return - // those along with resolved values for the star operations. - (oSum.init zip oSum.tail, iSum.init zip iSum.tail, oStar, iStar) - } catch { - case c: StarCycleException => throw c.copy(loop = context +: c.loop) - } - } - - /** Sequence of inward ports. - * - * This should be called after all star bindings are resolved. - * - * Each element is: - * `j` Port index of this binding in the Node's [[oPortMapping]] on the other side of the binding. - * `n` Instance of inward node. - * `p` View of [[Parameters]] where this connection was made. - * `s` Source info where this connection was made in the source code. - */ - protected[diplomacy] lazy val oDirectPorts: Seq[(Int, InwardNode[DO, UO, BO], Parameters, SourceInfo)] = oBindings.flatMap { case (i, n, _, p, s) => - // for each binding operator in this node, look at what it connects to - val (start, end) = n.iPortMapping(i) - (start until end) map { j => (j, n, p, s) } - } - - /** Sequence of outward ports. - * - * This should be called after all star bindings are resolved. - * - * `j` Port index of this binding in the Node's [[oPortMapping]] on the other side of the binding. - * `n` Instance of outward node. - * `p` View of [[Parameters]] where this connection was made. - * `s` [[SourceInfo]] where this connection was made in the source code. - */ - protected[diplomacy] lazy val iDirectPorts: Seq[(Int, OutwardNode[DI, UI, BI], Parameters, SourceInfo)] = iBindings.flatMap { case (i, n, _, p, s) => - // query this port index range of this node in the other side of node. - val (start, end) = n.oPortMapping(i) - (start until end) map { j => (j, n, p, s) } - } - - // Ephemeral nodes ( which have non-None iForward/oForward) have in_degree = out_degree - // Thus, there must exist an Eulerian path and the below algorithms terminate - @scala.annotation.tailrec - private def oTrace(tuple: (Int, InwardNode[DO, UO, BO], Parameters, SourceInfo)): (Int, InwardNode[DO, UO, BO], Parameters, SourceInfo) = - tuple match { case (i, n, p, s) => n.iForward(i) match { - case None => (i, n, p, s) - case Some ((j, m)) => oTrace((j, m, p, s)) - } } - - @scala.annotation.tailrec - private def iTrace(tuple: (Int, OutwardNode[DI, UI, BI], Parameters, SourceInfo)): (Int, OutwardNode[DI, UI, BI], Parameters, SourceInfo) = - tuple match { case (i, n, p, s) => n.oForward(i) match { - case None => (i, n, p, s) - case Some ((j, m)) => iTrace((j, m, p, s)) - } } - - /** Final output ports after all stars and port forwarding (e.g. [[EphemeralNode]]s) have been resolved. - * - * Each Port is a tuple of: - * - Numeric index of this binding in the [[InwardNode]] on the other end. - * - [[InwardNode]] on the other end of this binding. - * - A view of [[Parameters]] where the binding occurred. - * - [[SourceInfo]] for source-level error reporting. - */ - lazy val oPorts: Seq[(Int, InwardNode[DO, UO, BO], Parameters, SourceInfo)] = oDirectPorts.map(oTrace) - - /** Final input ports after all stars and port forwarding (e.g. [[EphemeralNode]]s) have been resolved. - * - * Each Port is a tuple of: - * - numeric index of this binding in [[OutwardNode]] on the other end. - * - [[OutwardNode]] on the other end of this binding. - * - a view of [[Parameters]] where the binding occurred. - * - [[SourceInfo]] for source-level error reporting. - */ - lazy val iPorts: Seq[(Int, OutwardNode[DI, UI, BI], Parameters, SourceInfo)] = iDirectPorts.map(iTrace) - - private var oParamsCycleGuard = false - protected[diplomacy] lazy val diParams: Seq[DI] = iPorts.map { case (i, n, _, _) => n.doParams(i) } - protected[diplomacy] lazy val doParams: Seq[DO] = { - try { - if (oParamsCycleGuard) throw DownwardCycleException() - oParamsCycleGuard = true - val o = mapParamsD(oPorts.size, diParams) - require (o.size == oPorts.size, - s"""Diplomacy has detected a problem with your graph: - |At the following node, the number of outward ports should equal the number of produced outward parameters. - |$context - |$connectedPortsInfo - |Downstreamed inward parameters: [${diParams.mkString(",")}] - |Produced outward parameters: [${o.mkString(",")}] - |""".stripMargin) - o.map(outer.mixO(_, this)) - } catch { - case c: DownwardCycleException => throw c.copy(loop = context +: c.loop) - } - } - - private var iParamsCycleGuard = false - protected[diplomacy] lazy val uoParams: Seq[UO] = oPorts.map { case (o, n, _, _) => n.uiParams(o) } - protected[diplomacy] lazy val uiParams: Seq[UI] = { - try { - if (iParamsCycleGuard) throw UpwardCycleException() - iParamsCycleGuard = true - val i = mapParamsU(iPorts.size, uoParams) - require (i.size == iPorts.size, - s"""Diplomacy has detected a problem with your graph: - |At the following node, the number of inward ports should equal the number of produced inward parameters. - |$context - |$connectedPortsInfo - |Upstreamed outward parameters: [${uoParams.mkString(",")}] - |Produced inward parameters: [${i.mkString(",")}] - |""".stripMargin) - i.map(inner.mixI(_, this)) - } catch { - case c: UpwardCycleException => throw c.copy(loop = context +: c.loop) - } - } - - /** Outward edge parameters. */ - protected[diplomacy] lazy val edgesOut: Seq[EO] = (oPorts zip doParams).map { case ((i, n, p, s), o) => outer.edgeO(o, n.uiParams(i), p, s) } - - /** Inward edge parameters. */ - protected[diplomacy] lazy val edgesIn: Seq[EI] = (iPorts zip uiParams).map { case ((o, n, p, s), i) => inner.edgeI(n.doParams(o), i, p, s) } - - /** A tuple of the input edge parameters and output edge parameters for the edges bound to this node. - * - * If you need to access to the edges of a foreign Node, use this method (in/out create bundles). - */ - lazy val edges: Edges[EI, EO] = Edges(edgesIn, edgesOut) - - /** Create actual Wires corresponding to the Bundles parameterized by the outward edges of this node. */ - protected[diplomacy] lazy val bundleOut: Seq[BO] = edgesOut.map { e => - val x = Wire(outer.bundleO(e)).suggestName(s"${valName.name}Out") - // TODO: Don't care unconnected forwarded diplomatic signals for compatibility issue, - // In the future, we should add an option to decide whether allowing unconnected in the LazyModule - x := DontCare - x - } - - /** Create actual Wires corresponding to the Bundles parameterized by the inward edges of this node. */ - protected[diplomacy] lazy val bundleIn: Seq[BI] = edgesIn .map { e => - val x = Wire(inner.bundleI(e)).suggestName(s"${valName.name}In") - // TODO: Don't care unconnected forwarded diplomatic signals for compatibility issue, - // In the future, we should add an option to decide whether allowing unconnected in the LazyModule - x := DontCare - x - } - - private def emptyDanglesOut: Seq[Dangle] = oPorts.zipWithIndex.map { case ((j, n, _, _), i) => - Dangle( - source = HalfEdge(serial, i), - sink = HalfEdge(n.serial, j), - flipped= false, - name = wirePrefix + "out", - dataOpt= None) - } - private def emptyDanglesIn: Seq[Dangle] = iPorts.zipWithIndex.map { case ((j, n, _, _), i) => - Dangle( - source = HalfEdge(n.serial, j), - sink = HalfEdge(serial, i), - flipped= true, - name = wirePrefix + "in", - dataOpt=None) - } - - - /** Create the [[Dangle]]s which describe the connections from this node output to other nodes inputs. */ - protected[diplomacy] def danglesOut: Seq[Dangle] = emptyDanglesOut.zipWithIndex.map { - case (d,i) => d.copy(dataOpt = Some(bundleOut(i))) - } - - /** Create the [[Dangle]]s which describe the connections from this node input from other nodes outputs. */ - protected[diplomacy] def danglesIn: Seq[Dangle] = emptyDanglesIn.zipWithIndex.map { - case (d,i) => d.copy(dataOpt = Some(bundleIn(i))) - } - - private[diplomacy] var instantiated = false - - /** Gather Bundle and edge parameters of outward ports. - * - * Accessors to the result of negotiation to be used within - * [[LazyModuleImp]] Code. Should only be used within [[LazyModuleImp]] code - * or after its instantiation has completed. - */ - def out: Seq[(BO, EO)] = { - require(instantiated, s"$name.out should not be called until after instantiation of its parent LazyModule.module has begun") - bundleOut zip edgesOut - } - - /** Gather Bundle and edge parameters of inward ports. - * - * Accessors to the result of negotiation to be used within - * [[LazyModuleImp]] Code. Should only be used within [[LazyModuleImp]] code - * or after its instantiation has completed. - */ - def in: Seq[(BI, EI)] = { - require(instantiated, s"$name.in should not be called until after instantiation of its parent LazyModule.module has begun") - bundleIn zip edgesIn - } - - /** Actually instantiate this node during [[LazyModuleImp]] evaluation. - * Mark that it's safe to use the Bundle wires, - * instantiate monitors on all input ports if appropriate, - * and return all the dangles of this node. - */ - protected[diplomacy] def instantiate(): Seq[Dangle] = { - instantiated = true - if (!circuitIdentity) { - (iPorts zip in) foreach { - case ((_, _, p, _), (b, e)) => if (p(MonitorsEnabled)) inner.monitor(b, e) - } } - danglesOut ++ danglesIn - } - - protected[diplomacy] def cloneDangles(): Seq[Dangle] = emptyDanglesOut ++ emptyDanglesIn - - /** Connects the outward part of a node with the inward part of this node. */ - protected[diplomacy] def bind(h: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = { - val x = this // x := y - val y = h - val info = sourceLine(sourceInfo, " at ", "") - val i = x.iPushed - val o = y.oPushed - y.oPush(i, x, binding match { - case BIND_ONCE => BIND_ONCE - case BIND_FLEX => BIND_FLEX - case BIND_STAR => BIND_QUERY - case BIND_QUERY => BIND_STAR - }) - x.iPush(o, y, binding) - } - - /* Metadata for printing the node graph. */ - def inputs: Seq[(OutwardNode[DI, UI, BI], RenderedEdge)] = (iPorts zip edgesIn) map { case ((_, n, p, _), e) => - val re = inner.render(e) - (n, re.copy(flipped = re.flipped != p(RenderFlipped))) - } - /** Metadata for printing the node graph */ - def outputs: Seq[(InwardNode[DO, UO, BO], RenderedEdge)] = oPorts map { case (i, n, _, _) => (n, n.inputs(i)._2) } -} - -/** A [[MixedNode]] that may be extended with custom behavior. */ -abstract class MixedCustomNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( - inner: InwardNodeImp [DI, UI, EI, BI], - outer: OutwardNodeImp[DO, UO, EO, BO])( - implicit valName: ValName) - extends MixedNode(inner, outer) { - override def description = "custom" - def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) - def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] - def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] -} - -/** A [[NodeImp]] that may be extended with custom behavior. - * - * Different from a [[MixedNode]] in that the inner and outer [[NodeImp]]s are the same. - */ -abstract class CustomNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( - implicit valName: ValName) - extends MixedCustomNode(imp, imp) - -/** A JunctionNode creates multiple parallel arbiters. - * - * @example - * {{{ - * val jbar = LazyModule(new JBar) - * slave1.node := jbar.node - * slave2.node := jbar.node - * extras.node :=* jbar.node - * jbar.node :*= masters1.node - * jbar.node :*= masters2.node - * }}} - * - * In the above example, only the first two connections have their multiplicity specified. - * All the other connections include a '*' on the JBar's side, so the JBar decides the multiplicity. - * Thus, in this example, we get 2x crossbars with 2 masters like this: - * {slave1, extras.1} <= jbar.1 <= {masters1.1, masters2.1} - * {slave2, extras.2} <= jbar.2 <= {masters1.2, masters2,2} - * - * @example - * {{{ - * val jbar = LazyModule(new JBar) - * jbar.node :=* masters.node - * slaves1.node :=* jbar.node - * slaves2.node :=* jbar.node - * }}} - * In the above example, the first connection takes multiplicity (*) from the right (masters). - * Supposing masters.node had 3 edges, this would result in these three arbiters: - * {slaves1.1, slaves2.1} <= jbar.1 <= { masters.1 } - * {slaves1.2, slaves2.2} <= jbar.2 <= { masters.2 } - * {slaves1.3, slaves2.3} <= jbar.3 <= { masters.3 } - */ -class MixedJunctionNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( - inner: InwardNodeImp [DI, UI, EI, BI], - outer: OutwardNodeImp[DO, UO, EO, BO])( - dFn: Seq[DI] => Seq[DO], - uFn: Seq[UO] => Seq[UI])( - implicit valName: ValName) - extends MixedNode(inner, outer) { - protected[diplomacy] var multiplicity = 0 - - def uRatio: Int = iPorts.size / multiplicity - def dRatio: Int = oPorts.size / multiplicity - - override def description = "junction" - protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { - require (iKnown == 0 || oKnown == 0, - s"""Diplomacy has detected a problem with your graph: - |The following node appears left of a :=* or a := and right of a :*= or :=. Only one side may drive multiplicity. - |$context - |$bindingInfo - |""".stripMargin) - multiplicity = iKnown max oKnown - (multiplicity, multiplicity) - } - protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = - p.grouped(multiplicity).toList.transpose.map(dFn).transpose.flatten - protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = - p.grouped(multiplicity).toList.transpose.map(uFn).transpose.flatten - - def inoutGrouped: Seq[(Seq[(BI, EI)], Seq[(BO, EO)])] = { - val iGroups = in .grouped(multiplicity).toList.transpose - val oGroups = out.grouped(multiplicity).toList.transpose - iGroups zip oGroups - } -} - -/** A node type which has a fixed ratio between the number of input edges and output edges. - * - * The [[NodeImp]] on either side is the same. - * - * One example usage would be for putting down a series of 2:1 arbiters. - * - * Suppose you had N banks of L2 and wanted to connect those to two different driver crossbars. - * In that case you can do this: - * {{{ - * l2banks.node :*= jbar.node - * jbar.node :*= xbar1.node - * jbar.node :*= xbar2.node - * }}} - * If the L2 has 4 banks, now there are 4 egress ports on both xbar1 and xbar2 and they are arbitrated by the jbar. - */ -class JunctionNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( - dFn: Seq[D] => Seq[D], - uFn: Seq[U] => Seq[U])( - implicit valName: ValName) - extends MixedJunctionNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn) - -/** [[MixedAdapterNode]] is used to transform between different diplomacy protocols ([[NodeImp]]), without changing the number of edges passing through it. - * - * For example, a [[MixedAdapterNode]] is needed for a TL to AXI bridge (interface). - * {{{ - * case class TLToAXI4Node(stripBits: Int = 0)(implicit valName: ValName) extends MixedAdapterNode(TLImp, AXI4Imp) - * }}} - * - * @param dFn convert downward parameter from input to output. - * @param uFn convert upward parameter from output to input. - */ -class MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( - inner: InwardNodeImp [DI, UI, EI, BI], - outer: OutwardNodeImp[DO, UO, EO, BO])( - dFn: DI => DO, - uFn: UO => UI)( - implicit valName: ValName) - extends MixedNode(inner, outer) { - override def description = "adapter" - protected[diplomacy] override def flexibleArityDirection = true - protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { - require (oStars + iStars <= 1, - s"""Diplomacy has detected a problem with your graph: - |The following node appears left of a :*= $iStars times and right of a :=* $oStars times, at most once is allowed. - |$context - |$bindingInfo - |""".stripMargin) - if (oStars > 0) { - require (iKnown >= oKnown, - s"""Diplomacy has detected a problem with your graph: - |After being connected right of :=*, the following node appears left of a := $iKnown times and right of a := $oKnown times. - |${iKnown - oKnown} additional right of := bindings are required to resolve :=* successfully. - |$context - |$bindingInfo - |""".stripMargin) - (0, iKnown - oKnown) - } else if (iStars > 0) { - require (oKnown >= iKnown, - s"""Diplomacy has detected a problem with your graph: - |After being connected left of :*=, the following node appears left of a := $iKnown times and right of a := $oKnown times. - |${oKnown - iKnown} additional left := bindings are required to resolve :*= successfully. - |$context - |$bindingInfo - |""".stripMargin) - (oKnown - iKnown, 0) - } else { - require (oKnown == iKnown, - s"""Diplomacy has detected a problem with your graph: - |The following node appears left of a := $iKnown times and right of a := $oKnown times. - |Either the number of bindings on both sides of the node match, or connect this node by left-hand side of :*= or right-hand side of :=* - |$context - |$bindingInfo - |""".stripMargin) - (0, 0) - } - } - protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = { - require(n == p.size, - s"""Diplomacy has detected a problem with your graph: - |The following node has ${p.size} inputs and $n outputs, they must match. - |$context - |$bindingInfo - |""".stripMargin) - p.map(dFn) - } - protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = { - require(n == p.size, - s"""Diplomacy has detected a problem with your graph: - |The following node has $n inputs and ${p.size} outputs, they must match - |$context - |$bindingInfo - |""".stripMargin) - p.map(uFn) - } -} - -/** A node which modifies the parameters flowing through it, but without changing the number of edges or the diplomatic protocol implementation. */ -class AdapterNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( - dFn: D => D, - uFn: U => U)( - implicit valName: ValName) - extends MixedAdapterNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn) - -/** A node which does not modify the parameters nor the protocol for edges that pass through it. - * - * During hardware generation, [[IdentityNode]]s automatically connect their inputs to outputs. - */ -class IdentityNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])()(implicit valName: ValName) - extends AdapterNode(imp)({ s => s }, { s => s }) { - override def description = "identity" - override final def circuitIdentity = true - override protected[diplomacy] def instantiate(): Seq[Dangle] = { - val dangles = super.instantiate() - (out zip in) foreach { case ((o, _), (i, _)) => o :<>= i } - dangles - } - override protected[diplomacy] def cloneDangles(): Seq[Dangle] = super.cloneDangles() -} - -/** [[EphemeralNode]]s are used as temporary connectivity placeholders, but disappear from the final node graph. - * An ephemeral node provides a mechanism to directly connect two nodes to each other where neither node knows about the other, - * but both know about an ephemeral node they can use to facilitate the connection. - */ -class EphemeralNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])()(implicit valName: ValName) - extends AdapterNode(imp)({ s => s }, { s => s }) { - override def description = "ephemeral" - override final def circuitIdentity = true - override def omitGraphML = true - override def oForward(x: Int): Option[(Int, OutwardNode[D, U, B])] = Some(iDirectPorts(x) match { case (i, n, _, _) => (i, n) }) - override def iForward(x: Int): Option[(Int, InwardNode[D, U, B])] = Some(oDirectPorts(x) match { case (i, n, _, _) => (i, n) }) - override protected[diplomacy] def instantiate(): Seq[Dangle] = { - instantiated = true - Nil - } - override protected[diplomacy] def cloneDangles(): Seq[Dangle] = Nil -} - -/** [[MixedNexusNode]] is used when the number of nodes connecting from either side is unknown (e.g. a Crossbar which also is a protocol adapter). - * - * The [[NodeImp]] is different between [[inner]] and [[outer]], - * - * @param dFn Function for mapping the parameters flowing downward into new outward flowing down parameters. - * @param uFn Function for mapping the parameters flowing upward into new inward flowing up parameters. - * @param inputRequiresOutput True if it is required that if there are input connections, there are output connections (this node can't just be a sink). - * @param outputRequiresInput True if it is required that if there are output connections, there are input connections (this node can't just be a source). - */ -class MixedNexusNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( - inner: InwardNodeImp [DI, UI, EI, BI], - outer: OutwardNodeImp[DO, UO, EO, BO])( - dFn: Seq[DI] => DO, - uFn: Seq[UO] => UI, - // no inputs and no outputs is always allowed - inputRequiresOutput: Boolean = true, - outputRequiresInput: Boolean = true)( - implicit valName: ValName) - extends MixedNode(inner, outer) -{ - override def description = "nexus" - protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { - // a nexus treats :=* as a weak pointer - def resolveStarInfo: String = - s"""$context - |$bindingInfo - |number of known := bindings to inward nodes: $iKnown - |number of known := bindings to outward nodes: $oKnown - |number of binding queries from inward nodes: $iStars - |number of binding queries from outward nodes: $oStars - |""".stripMargin - require(!outputRequiresInput || oKnown == 0 || iStars + iKnown != 0, - s"""Diplomacy has detected a problem with your graph: - |The following node has $oKnown outward connections and no inward connections. At least one inward connection was required. - |$resolveStarInfo - |""".stripMargin) - require(!inputRequiresOutput || iKnown == 0 || oStars + oKnown != 0, - s"""Diplomacy has detected a problem with your graph: - |The following node node has $iKnown inward connections and no outward connections. At least one outward connection was required. - |$resolveStarInfo - |""".stripMargin) - if (iKnown == 0 && oKnown == 0) (0, 0) else (1, 1) - } - protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = { if (n > 0) { val a = dFn(p); Seq.fill(n)(a) } else Nil } - protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = { if (n > 0) { val a = uFn(p); Seq.fill(n)(a) } else Nil } -} - -/** [[NexusNode]] is a [[MixedNexusNode]], in which the inward and outward side of the node have the same [[NodeImp]] implementation. */ -class NexusNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( - dFn: Seq[D] => D, - uFn: Seq[U] => U, - inputRequiresOutput: Boolean = true, - outputRequiresInput: Boolean = true)( - implicit valName: ValName) - extends MixedNexusNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn, inputRequiresOutput, outputRequiresInput) - -/** A node which represents a node in the graph which only has outward edges and no inward edges. - * - * A [[SourceNode]] cannot appear left of a `:=`, `:*=`, `:=*, or `:*=*` - * There are no Mixed [[SourceNode]]s, There are no "Mixed" [[SourceNode]]s because each one only has an outward side. - */ -class SourceNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(po: Seq[D])(implicit valName: ValName) - extends MixedNode(imp, imp) -{ - override def description = "source" - protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { - def resolveStarInfo: String = - s"""$context - |$bindingInfo - |number of known := bindings to inward nodes: $iKnown - |number of known := bindings to outward nodes: $oKnown - |number of binding queries from inward nodes: $iStars - |number of binding queries from outward nodes: $oStars - |${po.size} outward parameters: [${po.map(_.toString).mkString(",")}] - |""".stripMargin - require(oStars <= 1, - s"""Diplomacy has detected a problem with your graph: - |The following node appears right of a :=* $oStars times; at most once is allowed. - |$resolveStarInfo - |""".stripMargin) - require(iStars == 0, - s"""Diplomacy has detected a problem with your graph: - |The following node cannot appear left of a :*= - |$resolveStarInfo - |""".stripMargin) - require(iKnown == 0, - s"""Diplomacy has detected a problem with your graph: - |The following node cannot appear left of a := - |$resolveStarInfo - |""".stripMargin) - if (oStars == 0) - require(po.size == oKnown, - s"""Diplomacy has detected a problem with your graph: - |The following node has $oKnown outward bindings connected to it, but ${po.size} sources were specified to the node constructor. - |Either the number of outward := bindings should be exactly equal to the number of sources, or connect this node on the right-hand side of a :=* - |$resolveStarInfo - |""".stripMargin) - else - require(po.size >= oKnown, - s"""Diplomacy has detected a problem with your graph: - |The following node has $oKnown outward bindings connected to it, but ${po.size} sources were specified to the node constructor. - |To resolve :=*, size of outward parameters can not be less than bindings. - |$resolveStarInfo - |""".stripMargin - ) - (0, po.size - oKnown) - } - protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = po - protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = Seq() - - def makeIOs()(implicit valName: ValName): HeterogeneousBag[B] = { - val bundles = this.out.map(_._1) - val ios = IO(Flipped(new HeterogeneousBag(bundles))) - ios.suggestName(valName.name) - bundles.zip(ios).foreach { case (bundle, io) => bundle <> io } - ios - } -} - -/** A node which represents a node in the graph which has only inward edges, no outward edges. - * - * A [[SinkNode]] cannot appear cannot appear right of a `:=`, `:*=`, `:=*`, or `:*=*` - * - * There are no "Mixed" [[SinkNode]]s because each one only has an inward side. - */ -class SinkNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(pi: Seq[U])(implicit valName: ValName) - extends MixedNode(imp, imp) -{ - override def description = "sink" - protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { - def resolveStarInfo: String = - s"""$context - |$bindingInfo - |number of known := bindings to inward nodes: $iKnown - |number of known := bindings to outward nodes: $oKnown - |number of binding queries from inward nodes: $iStars - |number of binding queries from outward nodes: $oStars - |${pi.size} inward parameters: [${pi.map(_.toString).mkString(",")}] - |""".stripMargin - require (iStars <= 1, - s"""Diplomacy has detected a problem with your graph: - |The following node appears left of a :*= $iStars times; at most once is allowed. - |$resolveStarInfo - |""".stripMargin) - require (oStars == 0, - s"""Diplomacy has detected a problem with your graph: - |The following node cannot appear right of a :=* - |$resolveStarInfo - |""".stripMargin) - require (oKnown == 0, - s"""Diplomacy has detected a problem with your graph: - |The following node cannot appear right of a := - |$resolveStarInfo - |""".stripMargin) - if (iStars == 0) - require(pi.size == iKnown, - s"""Diplomacy has detected a problem with your graph: - |The following node has $iKnown inward bindings connected to it, but ${pi.size} sinks were specified to the node constructor. - |Either the number of inward := bindings should be exactly equal to the number of sink, or connect this node on the left-hand side of a :*= - |$resolveStarInfo - |""".stripMargin) - else - require(pi.size >= iKnown, - s"""Diplomacy has detected a problem with your graph: - |The following node has $iKnown inward bindings connected to it, but ${pi.size} sinks were specified to the node constructor. - |To resolve :*=, size of inward parameters can not be less than bindings. - |$resolveStarInfo - |""".stripMargin - ) - (pi.size - iKnown, 0) - } - protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = Seq() - protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = pi - - def makeIOs()(implicit valName: ValName): HeterogeneousBag[B] = { - val bundles = this.in.map(_._1) - val ios = IO(new HeterogeneousBag(bundles)) - ios.suggestName(valName.name) - bundles.zip(ios).foreach { case (bundle, io) => io <> bundle } - ios - } -} - -/** A node intended to replace a portion of the diplomatic graph in order to test functionality of a copy (cloned) [[LazyModule]] - * - * @param node the node to copy - * @param clone the copy of the LazyModule containing [[node]] - */ -class MixedTestNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] protected[diplomacy]( - node: NodeHandle [DI, UI, EI, BI, DO, UO, EO, BO], clone: CloneLazyModule)( - implicit valName: ValName) - extends MixedNode(node.inner, node.outer) -{ - // The devices connected to this test node must recreate these parameters: - def iParams: Seq[DI] = node.inward .diParams - def oParams: Seq[UO] = node.outward.uoParams - - override def description = "test" - protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { - def resolveStarInfo: String = - s"""$context - |$bindingInfo - |number of known := bindings to inward nodes: $iKnown - |number of known := bindings to outward nodes: $oKnown - |number of binding queries from inward nodes: $iStars - |number of binding queries from outward nodes: $oStars - |downstream inward parameters: ${node.inward.diParams} - |upstream inward parameters: ${node.inward.uiParams} - |upstream outward parameters: ${node.outward.uoParams} - |downstream outward parameters: ${node.outward.doParams} - |node.inward.uiParams.size - |""".stripMargin - - require(oStars <= 1, - s"""Diplomacy has detected a problem with your graph: - |The following node appears right of a :=* $oStars times; at most once is allowed. - |$resolveStarInfo - |""".stripMargin) - require(iStars <= 1, - s"""Diplomacy has detected a problem with your graph: - |The following node appears left of a :*= $iStars times; at most once is allowed. - |$resolveStarInfo - |""".stripMargin) - require(node.inward .uiParams.size == iKnown || iStars == 1, - s"""Diplomacy has detected a problem with your graph: - |The following node has only $iKnown inputs, which should be ${node.inward.uiParams.size}, or connect this node on the left-hand side of :*= - |$resolveStarInfo - |""".stripMargin) - require(node.outward.doParams.size == oKnown || oStars == 1, - s"""Diplomacy has detected a problem with your graph: - |The following node has only $oKnown outputs, which should be ${node.outward.doParams.size}, or connect this node on the right-hand side of :=* - |$resolveStarInfo - |""".stripMargin) - (node.inward.uiParams.size - iKnown, node.outward.doParams.size - oKnown) - } - - protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = node.inward .uiParams - protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = node.outward.doParams - - override protected[diplomacy] def instantiate(): Seq[Dangle] = { - val dangles = super.instantiate() - val orig_module = clone.base.module - val clone_auto = clone.io("auto").asInstanceOf[AutoBundle] - - danglesOut.zipWithIndex.foreach { case (d, i) => - val orig = orig_module.dangles.find(_.source == HalfEdge(node.outward.serial, i)) - require (orig.isDefined, s"Cloned node ${node.outward.name} must be connected externally out ${orig_module.name}") - val io_name = orig_module.auto.elements.find(_._2 eq orig.get.data).get._1 - d.data <> clone_auto.elements(io_name) - } - danglesIn.zipWithIndex.foreach { case (d, i) => - val orig = orig_module.dangles.find(_.sink == HalfEdge(node.inward.serial, i)) - require (orig.isDefined, s"Cloned node ${node.inward.name} must be connected externally in ${orig_module.name}") - val io_name = orig_module.auto.elements.find(_._2 eq orig.get.data).get._1 - clone_auto.elements(io_name) <> d.data - } - - dangles - } - override protected[diplomacy] def cloneDangles(): Seq[Dangle] = { - require(false, "Unsupported") - super.cloneDangles() - } -} diff --git a/src/main/scala/diplomacy/Resources.scala b/src/main/scala/diplomacy/Resources.scala index 4dc59d95304..0b3e3cb38c7 100644 --- a/src/main/scala/diplomacy/Resources.scala +++ b/src/main/scala/diplomacy/Resources.scala @@ -10,20 +10,26 @@ import scala.collection.mutable.HashMap sealed trait ResourceValue /** Permission of an address space. - * @param r readable. - * @param w writable. - * @param x executable. - * @param c cacheable. - * @param a supports all atomic operations. + * @param r + * readable. + * @param w + * writable. + * @param x + * executable. + * @param c + * cacheable. + * @param a + * supports all atomic operations. */ case class ResourcePermissions(r: Boolean, w: Boolean, x: Boolean, c: Boolean, a: Boolean) // Not part of DTS /** An address space description. - * @param address the address space. - * @param permissions the permission attributes of this space. See [[freechips.rocketchip.diplomacy.ResourcePermissions]]. + * @param address + * the address space. + * @param permissions + * the permission attributes of this space. See [[freechips.rocketchip.diplomacy.ResourcePermissions]]. */ -final case class ResourceAddress(address: Seq[AddressSet], permissions: ResourcePermissions) extends ResourceValue -{ +final case class ResourceAddress(address: Seq[AddressSet], permissions: ResourcePermissions) extends ResourceValue { /* For things like SPI which uses simple integer addressing */ def this(x: Int) = this(Seq(AddressSet(x, 0)), ResourcePermissions(false, false, false, false, false)) } @@ -32,13 +38,17 @@ object ResourceAddress { } /** A mapped address space (eg: when map a device to a bus). - * @param address the address space. - * @param offset the address offset of the mapped device (eg: base address of the bus). - * @param permissions the permission attributes of this space. See [[freechips.rocketchip.diplomacy.ResourcePermissions]]. + * @param address + * the address space. + * @param offset + * the address offset of the mapped device (eg: base address of the bus). + * @param permissions + * the permission attributes of this space. See [[freechips.rocketchip.diplomacy.ResourcePermissions]]. */ -final case class ResourceMapping(address: Seq[AddressSet], offset: BigInt, permissions: ResourcePermissions) extends ResourceValue +final case class ResourceMapping(address: Seq[AddressSet], offset: BigInt, permissions: ResourcePermissions) + extends ResourceValue final case class ResourceString(value: String) extends ResourceValue -final case class ResourceInt(value: BigInt) extends ResourceValue { +final case class ResourceInt(value: BigInt) extends ResourceValue { def this(x: Double) = this(BigDecimal(x).setScale(0, BigDecimal.RoundingMode.HALF_UP).toBigInt) } object ResourceInt { @@ -46,29 +56,30 @@ object ResourceInt { } /** A reference pointing to another device in DTS (eg: interrupt to interrupt controller). - * @param value the label (String) of the device. + * @param value + * the label (String) of the device. */ -final case class ResourceReference(value: String) extends ResourceValue -final case class ResourceAlias(value: String) extends ResourceValue +final case class ResourceReference(value: String) extends ResourceValue +final case class ResourceAlias(value: String) extends ResourceValue final case class ResourceMap(value: Map[String, Seq[ResourceValue]], labels: Seq[String] = Nil) extends ResourceValue /* If device is None, the value is global */ case class Binding(device: Option[Device], value: ResourceValue) -case class ResourceBindings(map: Map[String, Seq[Binding]] = Map.empty) -{ +case class ResourceBindings(map: Map[String, Seq[Binding]] = Map.empty) { def apply(key: String): Seq[Binding] = map.getOrElse(key, Nil) } /** A serializable description of a device. - * @param name the resolved name of this device. See [[freechips.rocketchip.diplomacy.DeviceRegName]]. - * @param mapping the property map of this device. + * @param name + * the resolved name of this device. See [[freechips.rocketchip.diplomacy.DeviceRegName]]. + * @param mapping + * the property map of this device. */ case class Description(name: String, mapping: Map[String, Seq[ResourceValue]]) case class ResourceBindingsMap(map: Map[Device, ResourceBindings]) -abstract class Device -{ +abstract class Device { def describe(resources: ResourceBindings): Description /* This can be overriden to make one device relative to another */ @@ -79,23 +90,20 @@ abstract class Device Device.index = Device.index + 1 } -abstract class DeviceSnippet extends Device -{ +abstract class DeviceSnippet extends Device { final def describe(resources: ResourceBindings) = describe() def describe(): Description ResourceBinding { Resource(this, "exists").bind(ResourceString("yes")) } } -object Device -{ +object Device { private var index: Int = 0 def skipIndexes(x: Int): Unit = { index += x } } /** A trait for devices that generate interrupts. */ -trait DeviceInterrupts -{ +trait DeviceInterrupts { this: Device => /** Whether to always use the expanded interrupt description in DTS: "interrupts-extended" */ @@ -103,20 +111,16 @@ trait DeviceInterrupts def describeInterrupts(resources: ResourceBindings): Map[String, Seq[ResourceValue]] = { val int = resources("int") - int.foreach { b => require (b.device.isDefined, s"Device ${this} property 'int' is missing user device") } + int.foreach { b => require(b.device.isDefined, s"Device ${this} property 'int' is missing user device") } val parents = int.map(_.device.get).distinct - val simple = parents.size == 1 && !alwaysExtended + val simple = parents.size == 1 && !alwaysExtended - val parent = - if (!simple) None else - Some("interrupt-parent" -> Seq(ResourceReference(parents.head.label))) - val interrupts = - if (!simple) None else - Some("interrupts" -> int.map(_.value)) + val parent = if (!simple) None else Some("interrupt-parent" -> Seq(ResourceReference(parents.head.label))) + val interrupts = if (!simple) None else Some("interrupts" -> int.map(_.value)) val interrupts_extended = - if (simple || parents.isEmpty) None else - Some("interrupts-extended" -> int.flatMap(b => Seq(ResourceReference(b.device.get.label), b.value))) + if (simple || parents.isEmpty) None + else Some("interrupts-extended" -> int.flatMap(b => Seq(ResourceReference(b.device.get.label), b.value))) ListMap() ++ parent ++ interrupts ++ interrupts_extended } @@ -125,22 +129,20 @@ trait DeviceInterrupts } /** A trait for devices that have an exposed clock. */ -trait DeviceClocks -{ +trait DeviceClocks { this: Device => /** The number of clocks this device must have; default to 0-1 */ val requiredClocks = 0 to 1 def describeClocks(resources: ResourceBindings): Map[String, Seq[ResourceValue]] = { val clocks = resources("clocks").map(_.value) - require (requiredClocks.contains(clocks.size)) + require(requiredClocks.contains(clocks.size)) if (!clocks.isEmpty) Map("clocks" -> clocks) else Map() } } /** A trait for resolving the name of a device. */ -trait DeviceRegName -{ +trait DeviceRegName { this: Device => def describeName(devname: String, resources: ResourceBindings): String = { val reg = resources.map.filterKeys(DiplomacyUtils.regFilter) @@ -148,8 +150,8 @@ trait DeviceRegName devname } else { val (named, bulk) = reg.partition { case (k, v) => DiplomacyUtils.regName(k).isDefined } - val mainreg = reg.head._2 - require (!mainreg.isEmpty, s"reg binding for $devname is empty!") + val mainreg = reg.head._2 + require(!mainreg.isEmpty, s"reg binding for $devname is empty!") mainreg.head.value match { case x: ResourceAddress => s"${devname}@${x.address.head.base.toString(16)}" case _ => require(false, s"Device has the wrong type of 'reg' property (${reg.head})"); "" @@ -163,49 +165,55 @@ trait DeviceRegName } object DiplomacyUtils { - def regFilter(name: String): Boolean = name == "reg" || name.take(4) == "reg/" + def regFilter(name: String): Boolean = name == "reg" || name.take(4) == "reg/" def rangeFilter(name: String): Boolean = name == "ranges" def regName(name: String): Option[String] = { val keys = name.split("/") - require (keys.size >= 1 && keys.size <= 2 && keys(0) == "reg", s"Invalid reg name '${name}'") + require(keys.size >= 1 && keys.size <= 2 && keys(0) == "reg", s"Invalid reg name '${name}'") if (keys.size == 1) None else Some(keys(1)) } } /** A simple device descriptor for devices that may support interrupts and address spaces. - * @param devname the base device named used in device name generation. - * @param devcompat a list of compatible devices. See device tree property "compatible". + * @param devname + * the base device named used in device name generation. + * @param devcompat + * a list of compatible devices. See device tree property "compatible". */ -class SimpleDevice(val devname: String, devcompat: Seq[String]) extends Device - with DeviceInterrupts - with DeviceClocks - with DeviceRegName -{ +class SimpleDevice(val devname: String, devcompat: Seq[String]) + extends Device + with DeviceInterrupts + with DeviceClocks + with DeviceRegName { override def parent = Some(ResourceAnchors.soc) // nearly everything on-chip belongs here var deviceNamePlusAddress: String = "" def describe(resources: ResourceBindings): Description = { - val name = describeName(devname, resources) // the generated device name in device tree - val int = describeInterrupts(resources) // interrupt description + val name = describeName(devname, resources) // the generated device name in device tree + val int = describeInterrupts(resources) // interrupt description val clocks = describeClocks(resources) def optDef(x: String, seq: Seq[ResourceValue]) = if (seq.isEmpty) None else Some(x -> seq) val compat = optDef("compatible", devcompat.map(ResourceString(_))) // describe the list of compatiable devices - val reg = resources.map.filterKeys(DiplomacyUtils.regFilter) + val reg = resources.map.filterKeys(DiplomacyUtils.regFilter) val (named, bulk) = reg.partition { case (k, v) => DiplomacyUtils.regName(k).isDefined } // We need to be sure that each named reg has exactly one AddressRange associated to it named.foreach { case (k, Seq(Binding(_, value: ResourceAddress))) => val ranges = AddressRange.fromSets(value.address) - require (ranges.size == 1, s"DTS device $name has $k = $ranges, must be a single range!") - case (k, seq) => - require (false, s"DTS device $name has $k = $seq, must be a single ResourceAddress!") + require(ranges.size == 1, s"DTS device $name has $k = $ranges, must be a single range!") + case (k, seq) => require(false, s"DTS device $name has $k = $seq, must be a single ResourceAddress!") } - val names = optDef("reg-names", named.map(x => ResourceString(DiplomacyUtils.regName(x._1).get)).toList) // names of the named address space - val regs = optDef("reg", (named ++ bulk).flatMap(_._2.map(_.value)).toList) // address ranges of all spaces (named and bulk) + val names = + optDef( + "reg-names", + named.map(x => ResourceString(DiplomacyUtils.regName(x._1).get)).toList + ) // names of the named address space + val regs = + optDef("reg", (named ++ bulk).flatMap(_._2.map(_.value)).toList) // address ranges of all spaces (named and bulk) deviceNamePlusAddress = name @@ -214,28 +222,32 @@ class SimpleDevice(val devname: String, devcompat: Seq[String]) extends Device } /** A simple bus - * @param devname the base device named used in device name generation. - * @param devcompat a list of compatible devices. See device tree property "compatible". - * @param offset the base address of this bus. + * @param devname + * the base device named used in device name generation. + * @param devcompat + * a list of compatible devices. See device tree property "compatible". + * @param offset + * the base address of this bus. */ -class SimpleBus(devname: String, devcompat: Seq[String], offset: BigInt = 0) extends SimpleDevice(devname, devcompat ++ Seq("simple-bus")) -{ +class SimpleBus(devname: String, devcompat: Seq[String], offset: BigInt = 0) + extends SimpleDevice(devname, devcompat ++ Seq("simple-bus")) { override def describe(resources: ResourceBindings): Description = { - val ranges = resources("ranges").collect { - case Binding(_, a: ResourceAddress) => ResourceMapping(a.address, offset, a.permissions) + val ranges = resources("ranges").collect { case Binding(_, a: ResourceAddress) => + ResourceMapping(a.address, offset, a.permissions) } - require (!ranges.isEmpty, s"SimpleBus $devname must set ranges") + require(!ranges.isEmpty, s"SimpleBus $devname must set ranges") - val map = AddressRange.fromSets(ranges.flatMap(_.address)) + val map = AddressRange.fromSets(ranges.flatMap(_.address)) val minBase = map.map(_.base).min val maxBase = map.map(_.end).max val maxSize = map.map(_.size).max def ofInt(x: Int) = Seq(ResourceInt(BigInt(x))) val extra = Map( - "#address-cells" -> ofInt((log2Ceil(maxBase) + 31) / 32), - "#size-cells" -> ofInt((log2Ceil(maxSize) + 31) / 32), - "ranges" -> ranges) + "#address-cells" -> ofInt((log2Ceil(maxBase) + 31) / 32), + "#size-cells" -> ofInt((log2Ceil(maxSize) + 31) / 32), + "ranges" -> ranges + ) deviceNamePlusAddress = devname @@ -245,42 +257,45 @@ class SimpleBus(devname: String, devcompat: Seq[String], offset: BigInt = 0) ext def ranges = Seq(Resource(this, "ranges")) } + /** A generic memory block. */ -class MemoryDevice extends Device with DeviceRegName -{ +class MemoryDevice extends Device with DeviceRegName { def describe(resources: ResourceBindings): Description = { - Description(describeName("memory", resources), ListMap( - "reg" -> resources.map.filterKeys(DiplomacyUtils.regFilter).flatMap(_._2).map(_.value).toList, - "device_type" -> Seq(ResourceString("memory")))) + Description( + describeName("memory", resources), + ListMap( + "reg" -> resources.map.filterKeys(DiplomacyUtils.regFilter).flatMap(_._2).map(_.value).toList, + "device_type" -> Seq(ResourceString("memory")) + ) + ) } } -case class Resource(owner: Device, key: String) -{ +case class Resource(owner: Device, key: String) { def bind(user: Device, value: ResourceValue): Unit = { val scope = BindingScope.active.get scope.resourceBindings = (this, Some(user), value) +: scope.resourceBindings } - def bind(value: ResourceValue): Unit = { + def bind(value: ResourceValue): Unit = { val scope = BindingScope.active.get scope.resourceBindings = (this, None, value) +: scope.resourceBindings } } /** The resource binding scope for a LazyModule that generates a device tree (currently Subsystem only). */ -trait BindingScope -{ +trait BindingScope { this: LazyModule => BindingScope.add(this) private val parentScope = BindingScope.find(parent) - protected[diplomacy] var resourceBindingFns: Seq[() => Unit] = Nil // callback functions to resolve resource binding during elaboration + protected[diplomacy] var resourceBindingFns: Seq[() => Unit] = + Nil // callback functions to resolve resource binding during elaboration protected[diplomacy] var resourceBindings: Seq[(Resource, Option[Device], ResourceValue)] = Nil private case class ExpandedValue(path: Seq[String], labels: Seq[String], value: Seq[ResourceValue]) private lazy val eval: Unit = { - require (!LazyModule.scope.isDefined, "May not evaluate binding while still constructing LazyModules") + require(!LazyModule.getScope.isDefined, "May not evaluate binding while still constructing LazyModules") parentScope.foreach { _.eval } resourceBindings = parentScope.map(_.resourceBindings).getOrElse(Nil) BindingScope.active = Some(this) @@ -291,55 +306,60 @@ trait BindingScope private def makeTree(list: Seq[ExpandedValue]): Seq[ResourceValue] = { val (values_p, keys_p) = list.partition(_.path.isEmpty) - val values = values_p.flatMap(_.value) - val labels = values_p.flatMap(_.labels) - val keys = keys_p.groupBy(_.path.head).toList.map { case (key, seq) => + val values = values_p.flatMap(_.value) + val labels = values_p.flatMap(_.labels) + val keys = keys_p.groupBy(_.path.head).toList.map { case (key, seq) => (key -> makeTree(seq.map { x => x.copy(path = x.path.tail) })) } - if (labels.isEmpty && keys.isEmpty) values else ResourceMap(SortedMap(keys:_*), labels) +: values + if (labels.isEmpty && keys.isEmpty) values else ResourceMap(SortedMap(keys: _*), labels) +: values } private def expand(path: Seq[String], values: Seq[ResourceValue]): Seq[ExpandedValue] = { ExpandedValue(path, Nil, Nil) +: - values.flatMap { - case ResourceMap(map, labels) => - ExpandedValue(path, labels, Nil) +: - map.toList.flatMap { case (key, values) => expand(path :+ key, values) } - case z => Seq(ExpandedValue(path, Nil, Seq(z))) - } + values.flatMap { + case ResourceMap(map, labels) => ExpandedValue(path, labels, Nil) +: + map.toList.flatMap { case (key, values) => expand(path :+ key, values) } + case z => Seq(ExpandedValue(path, Nil, Seq(z))) + } } - private def collect(skipRoot: Int, path: List[String], offset: BigInt, map: ResourceMap): List[(String, ResourceAddress)] = { + private def collect(skipRoot: Int, path: List[String], offset: BigInt, map: ResourceMap) + : List[(String, ResourceAddress)] = { // Translate local addresses to global addresses val name = path.headOption.getOrElse("/") def shift(x: Seq[AddressSet]) = x.map(a => a.copy(base = a.base + offset)) - val addresses: List[(String, ResourceAddress)] = map.value.toList.flatMap { case (_, seq) => seq.collect { - case y: ResourceAddress => (name -> y.copy(address = shift(y.address))) - } } + val addresses: List[(String, ResourceAddress)] = map.value.toList.flatMap { case (_, seq) => + seq.collect { case y: ResourceAddress => + (name -> y.copy(address = shift(y.address))) + } + } // Recursively handle children only if they use addresses val haveChildAddresses = map.value.values.exists(_.exists { case x: ResourceMap => x.value.contains("reg") || x.value.contains("ranges") case _ => false }) - def mapChildren(offset: BigInt) = map.value.toList.flatMap { case (key, seq) => seq.collect { - case map: ResourceMap => collect(skipRoot, key :: path, offset, map) - }.flatten } + def mapChildren(offset: BigInt) = map.value.toList.flatMap { case (key, seq) => + seq.collect { case map: ResourceMap => + collect(skipRoot, key :: path, offset, map) + }.flatten + } // How do we handle this node? val childAddresses = map.value.lift("ranges") match { // root typically is missing ranges; probe children anyway - case None if path.size < skipRoot => mapChildren(offset) + case None if path.size < skipRoot => mapChildren(offset) // no ranges -> don't probe children - case None => Nil + case None => Nil // ranges; -> probe children at same offset - case Some(Nil) => mapChildren(offset) + case Some(Nil) => mapChildren(offset) // ranges x; + no children -> report ranges as addressable regions - case Some(seq) if !haveChildAddresses => seq.collect { - case ResourceMapping(addr, _, perm) => (name -> ResourceAddress(shift(addr), perm)) - } + case Some(seq) if !haveChildAddresses => + seq.collect { case ResourceMapping(addr, _, perm) => + (name -> ResourceAddress(shift(addr), perm)) + } // children + single ranges -> probe children at displaced offset - case Some(Seq(ResourceMapping(addr, delta, perm))) => mapChildren(offset+delta) + case Some(Seq(ResourceMapping(addr, delta, perm))) => mapChildren(offset + delta) // multiple ranges + children -> don't know how to handle this - case x => { require(false, s"Unexpected value in ranges key: ${x}"); Nil } + case x => { require(false, s"Unexpected value in ranges key: ${x}"); Nil } } addresses ++ childAddresses } @@ -347,19 +367,19 @@ trait BindingScope /** Generate the device tree. */ def bindingTree: ResourceMap = { eval - val map: Map[Device, ResourceBindings] = getResourceBindingsMap.map - val descs: HashMap[Device, Description] = HashMap.empty - def getDesc(dev: Device): Description = { + val map: Map[Device, ResourceBindings] = getResourceBindingsMap.map + val descs: HashMap[Device, Description] = HashMap.empty + def getDesc(dev: Device): Description = { if (descs.contains(dev)) { descs(dev) } else { - val bindings = map.lift(dev).getOrElse(ResourceBindings()) + val bindings = map.lift(dev).getOrElse(ResourceBindings()) val Description(name, mapping) = dev.describe(bindings) - val fullName = dev.parent match { - case None => name + val fullName = dev.parent match { + case None => name case Some(parent) => getDesc(parent).name + "/" + name } - val desc = Description(fullName, mapping) + val desc = Description(fullName, mapping) descs += ((dev, desc)) desc } @@ -367,7 +387,8 @@ trait BindingScope map.keys.foreach(getDesc) val tree = makeTree(descs.toList.flatMap { case (d, Description(name, mapping)) => val tokens = name.split("/").toList - expand(tokens, Seq(ResourceMap(mapping, Seq(d.label)))) }) + expand(tokens, Seq(ResourceMap(mapping, Seq(d.label)))) + }) ResourceMap(SortedMap("/" -> tree)) } @@ -377,20 +398,25 @@ trait BindingScope */ def getResourceBindingsMap: ResourceBindingsMap = { eval - ResourceBindingsMap(map = resourceBindings.reverse.groupBy(_._1.owner).mapValues(seq => ResourceBindings( - seq.groupBy(_._1.key).mapValues(_.map(z => Binding(z._2, z._3)).distinct).toMap)).toMap) + ResourceBindingsMap(map = + resourceBindings.reverse + .groupBy(_._1.owner) + .mapValues(seq => + ResourceBindings(seq.groupBy(_._1.key).mapValues(_.map(z => Binding(z._2, z._3)).distinct).toMap) + ) + .toMap + ) } /** Collect resource addresses from tree. */ def collectResourceAddresses = collect(2, Nil, 0, bindingTree) } -object BindingScope -{ - protected[diplomacy] var active: Option[BindingScope] = None - protected[diplomacy] def find(m: Option[LazyModule] = LazyModule.scope): Option[BindingScope] = m.flatMap { - case x: BindingScope => find(x.parent).orElse(Some(x)) - case x => find(x.parent) +object BindingScope { + protected[diplomacy] var active: Option[BindingScope] = None + protected[diplomacy] def find(m: Option[LazyModule] = LazyModule.getScope): Option[BindingScope] = m.flatMap { + case x: BindingScope => find(x.getParent).orElse(Some(x)) + case x => find(x.getParent) } var bindingScopes = new collection.mutable.ArrayBuffer[BindingScope]() @@ -398,42 +424,37 @@ object BindingScope def add(bs: BindingScope) = BindingScope.bindingScopes.+=:(bs) } -object ResourceBinding -{ +object ResourceBinding { + /** Add a resource callback function to the callback list BindingScope.resourceBindingFns. - * @param block the callback function to be added. + * @param block + * the callback function to be added. */ def apply(block: => Unit): Unit = { val scope = BindingScope.find() - require (scope.isDefined, "ResourceBinding must be called from within a BindingScope") + require(scope.isDefined, "ResourceBinding must be called from within a BindingScope") scope.get.resourceBindingFns = { () => block } +: scope.get.resourceBindingFns } } -object ResourceAnchors -{ +object ResourceAnchors { val root = new Device { def describe(resources: ResourceBindings): Description = { - val width = resources("width").map(_.value) - val model = resources("model").map(_.value) + val width = resources("width").map(_.value) + val model = resources("model").map(_.value) val compat = resources("compat").map(_.value) - Description("/", Map( - "#address-cells" -> width, - "#size-cells" -> width, - "model" -> model, - "compatible" -> compat)) + Description("/", Map("#address-cells" -> width, "#size-cells" -> width, "model" -> model, "compatible" -> compat)) } } val soc = new Device { def describe(resources: ResourceBindings): Description = { - val width = resources("width").map(_.value) + val width = resources("width").map(_.value) val compat = resources("compat").map(_.value) :+ ResourceString("simple-bus") - Description("soc", Map( - "#address-cells" -> width, - "#size-cells" -> width, - "compatible" -> compat, - "ranges" -> Nil)) + Description( + "soc", + Map("#address-cells" -> width, "#size-cells" -> width, "compatible" -> compat, "ranges" -> Nil) + ) } } @@ -441,17 +462,18 @@ object ResourceAnchors def describe(resources: ResourceBindings): Description = { val width = resources("width").map(_.value) val hertz = resources("hertz").map(_.value) - Description("cpus", Map( - "#address-cells" -> width, - "#size-cells" -> Seq(ResourceInt(0)), - "timebase-frequency" -> hertz)) + Description( + "cpus", + Map("#address-cells" -> width, "#size-cells" -> Seq(ResourceInt(0)), "timebase-frequency" -> hertz) + ) } } val aliases = new Device { - def describe(resources: ResourceBindings): Description = - Description("aliases", Map() ++ - resources("uart").zipWithIndex.map { case (Binding(_, value), i) => - (s"serial${i}" -> Seq(value))}) + def describe(resources: ResourceBindings): Description = Description( + "aliases", + Map() ++ + resources("uart").zipWithIndex.map { case (Binding(_, value), i) => (s"serial${i}" -> Seq(value)) } + ) } } diff --git a/src/main/scala/diplomacy/ValName.scala b/src/main/scala/diplomacy/ValName.scala deleted file mode 100644 index bf0e5812298..00000000000 --- a/src/main/scala/diplomacy/ValName.scala +++ /dev/null @@ -1,12 +0,0 @@ -// See LICENSE.SiFive for license details. - -package freechips.rocketchip.diplomacy - -import freechips.rocketchip.macros.ValNameImpl - -case class ValName(name: String) - -object ValName -{ - implicit def materialize(implicit x: ValNameImpl): ValName = ValName(x.name) -} diff --git a/src/main/scala/diplomacy/package.scala b/src/main/scala/diplomacy/package.scala index 5433147fae1..3ac4bde9310 100644 --- a/src/main/scala/diplomacy/package.scala +++ b/src/main/scala/diplomacy/package.scala @@ -2,192 +2,17 @@ package freechips.rocketchip -import chisel3.experimental.{SourceInfo, SourceLine} import chisel3.Data +import chisel3.experimental.{SourceInfo, SourceLine} import org.chipsalliance.cde.config.Parameters -import scala.language.implicitConversions +import scala.language.implicitConversions -/** Diplomacy is a set of abstractions for describing directed, acyclic graphs - * where parameters will be negotiated between nodes. These abstractions are - * expressed in the form of abstract classes, traits, and type parameters, which - * comprises nearly all of the types defined in this package. - * - * The [[NodeImp]] ("node implementation") is the main abstract type that associates - * the type parameters of all other abstract types. Defining a concrete - * implementation of [[NodeImp]] will therefore determine concrete types for all - * type parameters. For example, passing in a concrete instance of NodeImp to a - * SourceNode will fully determine concrete types for all of a SourceNode's type - * parameters. - * - * Specific applications of Diplomacy are expected to either extend these types - * or to specify concrete types for the type parameters. This allows for - * creating and associating application-specific node, edge, parameter, and bundle types. - * - * - * =Concepts, metaphors, and mnemonics to help with understanding Diplomacy code= - * - * ==Parameter Types== - * - * There are several types of parameters involved in diplomacy code. - * - * - Upward-flowing/Downward-flowing Parameters: These parameter types flow along edges and can be considered as the - * pre-negotiated, unresolved parameters. - * - Edge Parameters: These parameters are the result of the diplomatic negotiation and that is resolved for each edge. - * They are metadata, or an abstract concept of the connection represented by their edge, and contain any sort. - * These are an abstract concept which carry any sort of conceptual information that is useful to pass along the graph edge. - * For example, the full address map visible from a given edge and the supported access types for each memory region. - * - "p" Parameters: These are parameters of type [[Parameters]] which are implicit and generally available - * in various stages of the diplomacy codebase. - * Often they are captured from the context in which a particular diplomatic node or edge is created or bound. - * - Bundle Parameters: These parameters are used for actual hardware generation of the [[chisel3.Data]]s which connect - * diplomatic components. In contrast to edge parameters, this may carry information like the width of an address - * or opcode field. - * While they are derived from Edge parameters holding all metadata computed over an edge, - * Bundle parameters often contain only concrete information required to create the hardware type, - * such as [[freechips.rocketchip.tilelink.TLBundleParameters]] and [[freechips.rocketchip.amba.axi4.AXI4BundleParameters]] - * - * ==Inward/Outward vs. Upward/Downward== - * - * Diplomacy defines two dimensions: inward/outward and upward/downward. - * - * Inward/outward refer to the direction of edges from the perspective of a given node. - * For a given node: - * - Inward refers to edges that point into itself. - * - Outward refers to edges that point out from itself. - * - * Therefore, a given edge is always described as inward to one node and as outward from another. - * - * Upward/downward refer to the direction of the overall directed acyclic graph. - * Because each each edge is directed, we say that the directions flow from sources (nodes that only have outward edges) - * downwards to sinks (nodes that only have inward edges), or from sinks upwards to sources. - * These terms are used in parameter negotiation, where parameters flow both - * upwards and downwards on edges. Note that diplomacy avoids terms like "master/slave", - * "producer/consumer", though these can be defined by the concrete implementations of diplomatic systems. - * Such terms imply something about the transactional behavior of agents within a protocol, - * whereas source/sink and up/down refer only to the structure of the graph and the flow of parameters. - * - Upward refers to the flow of parameters along edges in the upwards direction. - * - Downward refers to a flow of parameters along edges in the downwards direction. - * - * A useful mnemonic for distinguishing between upward and downward is to imagine - * a diplomatic graph as a literal network of rivers where water flows in the direction of the edges, - * and parameters that move in the upstream direction, - * while downward refers to parameters that move in the downstream direction. - * - * ==Acronyms== - * - * Diplomacy has some commonly used acronyms described below: - * D[IO], U[IO], E[IO], B[IO] are the types of parameters which will be propagated. - * D: Downwards -- parameters passed in the same direction as the edge. - * U: Upwards -- parameters passed in the opposite direction as the edge. - * E: Edge -- resolved (negotiated) parameters describing conceptual information on graph edges. - * B: Bundle should extends from [[chisel3.Data]]. - * - * {{{ - * - * - * Upwards (a.k.a. towards Sources) ↓ - * ↓ - * inward edge of (parameter) type EI ↓ - * created from parameters of type UI and DI ↓ - * will result in a Bundle of type BI ↓ - * ↓ - * ^ ↓ * - * . ↓ * - * ┌───────────────────────────────.──↓──*───────────────────────────────┐ - * │ . ↓ * BaseNode │ - * │ . ↓ * (NodeImp) │ - * │ . ↓ * │ - * │ ┌────────────────────────────.──↓──*────────────────────────────┐ │ - * │ │ . ↓ * InwardNode (InwardNodeImp)│ │ - * │ │ (mixI)↓ * │ │ - * │ │ . ↓ * │ │ - * │ │ Upward-flowing inwards . ↓ * Downward-Flowing inwards │ │ - * │ │ parameters of type UI . ↓ * parameters of type DI │ │ - * │ └────────────────────────────.──↓──*────────────────────────────┘ │ - * │ . ↓ * │ - * │ . I v │ - * │ (mapParamsU) (mapParamsD) │ - * │ ^ O + │ - * │ : ↓ + │ - * │ ┌────────────────────────────:──↓──+────────────────────────────┐ │ - * │ │ : ↓ + OutwardNode(OutwardNodeImp)│ │ - * │ │ : ↓ (mixO) │ │ - * │ │ : ↓ + │ │ - * │ │ Upward-flowing outwards : ↓ + Downward-Flowing outward │ │ - * │ │ parameters of type UO : ↓ + parameters of type DO │ │ - * │ └────────────────────────────:──↓──+────────────────────────────┘ │ - * │ : ↓ + │ - * │ : ↓ + │ - * └───────────────────────────────.──↓──*───────────────────────────────┘ - * : ↓ * - * : ↓ v - * ↓ outward edge of (parameter) type EO - * ↓ created from parameters of type UO and DO - * ↓ will result in a Bundle of type BO - * ↓ - * ↓ Downwards (a.k.a. towards Sinks) - * - * }}} - * - * == Handles == - * - * Two Diplomatic nodes can be bound together using the `:=` operator or one of - * its sibling operators. Binding is asymmetric, and the binding operation will - * connect the outward of one node to the inward of the other. - * - * For example, the expression `a := b` will connect the outward of `b` to the - * inward of `a`. - * - * We would like the `:=` operator to have additional properties that make it - * intuitive to use: - * - * 1. It should be chainable, so that `a := b := c` will have the intuitive effect - * of binding c to b and b to a. This requires that the return type of `:=` be the - * same as its arguments, because the result of one `:=` operation must be - * valid as an argument to other `:=` operations. - * - * 2. It should be associative, so that `(a := b) := c` is equivalent to `a := (b := c).` - * This means that the order in which the bind operations execute does - * not matter, even if split across multiple files. - * - * 3. `a := b` should only be allowed if and only if `b` allows outward edges and `a` - * allows inward edges. This should be preserved even when chaining - * operations, and it should ideally be enforced at compile time. - * - * [[NodeHandle]] are a way of satisfying all of these properties. A Handle represents - * the aggregation of a chain of Nodes, and it preserves information about - * the connectability of the innermost and the outermost sides of the chain. - * - * If `b` supports inward edges, then `a := b` returns a [[NodeHandle]] that supports inward - * edges that go into `b`. If `a` supports outward edges, then `a := b` returns a - * [[NodeHandle]] that supports outward edges coming out of `a`. - * - * ==Node Terms== - * - * These are some conventionally used terms for diplomatic Nodes, - * which describe different common subtypes that certain protocol implementation might utilize: - * - Mixed: implies that the inward and outward NodeImp are not the same (some sort of protocol conversion is occurring between the two implementations). - * - Adapter: the number of inward and outward edges must be the same. - * - Nexus: the number of nodes connecting from either side are unknown until the graph is constructed and can differ from one another. - * - Identity: modifies neither the parameters nor the protocol-specific circuitry for the edges that pass through it. - * - Source: cannot have inward edges. - * - Sink: cannot have outward edges. - * - Junction: the number of inward and outward edges must have a fixed ratio to one another - * - Ephemeral: a temporary placeholder used for connectivity operations +/** Rocketchip Specific Diplomacy code. All other Diplomacy core functionality has been moved to standalone diplomacy */ -package object diplomacy -{ - type SimpleNodeHandle[D, U, E, B <: Data] = NodeHandle[D, U, E, B, D, U, E, B] - type AnyMixedNode = MixedNode[_, _, _, _ <: Data, _, _, _, _ <: Data] - - def sourceLine(sourceInfo: SourceInfo, prefix: String = " (", suffix: String = ")") = sourceInfo match { - case SourceLine(filename, line, col) => s"$prefix$filename:$line:$col$suffix" - case _ => "" - } - +package object diplomacy { def bitIndexes(x: BigInt, tail: Seq[Int] = Nil): Seq[Int] = { - require (x >= 0) + require(x >= 0) if (x == 0) { tail.reverse } else { @@ -204,7 +29,7 @@ package object diplomacy } type PropertyOption = Option[(String, Seq[ResourceValue])] - type PropertyMap = Iterable[(String, Seq[ResourceValue])] + type PropertyMap = Iterable[(String, Seq[ResourceValue])] implicit class IntToProperty(x: Int) { def asProperty: Seq[ResourceValue] = Seq(ResourceInt(BigInt(x))) @@ -222,21 +47,230 @@ package object diplomacy def asProperty: Seq[ResourceValue] = Seq(ResourceReference(x.label)) } - def EnableMonitors[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial { - case MonitorsEnabled => true - }) - def DisableMonitors[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial { - case MonitorsEnabled => false - }) - def FlipRendering[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial { - case RenderFlipped => !p(RenderFlipped) - }) + implicit def noCrossing(value: NoCrossing.type): ClockCrossingType = SynchronousCrossing(BufferParams.none) + + // TODO - Remove compatibility layer for deprecated diplomacy api once all local references are moved to standalone diplomacy lib. + // package.scala + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + def sourceLine(sourceInfo: SourceInfo, prefix: String = " (", suffix: String = ")") = sourceInfo match { + case SourceLine(filename, line, col) => s"$prefix$filename:$line:$col$suffix" + case _ => "" + } + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + def EnableMonitors[T]( + body: Parameters => T + )( + implicit p: Parameters + ) = _root_.org.chipsalliance.diplomacy.EnableMonitors(body)(p) + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + def DisableMonitors[T]( + body: Parameters => T + )( + implicit p: Parameters + ) = _root_.org.chipsalliance.diplomacy.DisableMonitors(body)(p) + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + def FlipRendering[T]( + body: Parameters => T + )( + implicit p: Parameters + ) = _root_.org.chipsalliance.diplomacy.FlipRendering(body)(p) + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + implicit def moduleValue[T](value: ModuleValue[T]): T = _root_.org.chipsalliance.diplomacy.moduleValue(value) - implicit def moduleValue[T](value: ModuleValue[T]): T = value.getWrappedValue +// Clone.scala + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val CloneLazyModule = _root_.org.chipsalliance.diplomacy.lazymodule.CloneLazyModule - implicit def noCrossing(value: NoCrossing.type): ClockCrossingType = SynchronousCrossing(BufferParams.none) +// ValName.scala + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type ValName = _root_.org.chipsalliance.diplomacy.ValName + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + def ValName(value: String) = _root_.org.chipsalliance.diplomacy.ValName(value) + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + implicit def SourcecodeNameExt(x: sourcecode.Name) = _root_.org.chipsalliance.diplomacy.SourcecodeNameExt(x) + +// LazyModule.scala + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type LazyModule = _root_.org.chipsalliance.diplomacy.lazymodule.LazyModule + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val LazyModule = _root_.org.chipsalliance.diplomacy.lazymodule.LazyModule + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type LazyModuleImpLike = _root_.org.chipsalliance.diplomacy.lazymodule.LazyModuleImpLike + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type LazyModuleImp = _root_.org.chipsalliance.diplomacy.lazymodule.LazyModuleImp + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type LazyRawModuleImp = _root_.org.chipsalliance.diplomacy.lazymodule.LazyRawModuleImp + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type SimpleLazyModule = _root_.org.chipsalliance.diplomacy.lazymodule.SimpleLazyModule + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type LazyScope = _root_.org.chipsalliance.diplomacy.lazymodule.LazyScope + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val LazyScope = _root_.org.chipsalliance.diplomacy.lazymodule.LazyScope + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type ModuleValue[T] = _root_.org.chipsalliance.diplomacy.lazymodule.ModuleValue[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val InModuleBody = _root_.org.chipsalliance.diplomacy.lazymodule.InModuleBody + +// Nodes.scala + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type Dangle = _root_.org.chipsalliance.diplomacy.nodes.Dangle + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val Dangle = _root_.org.chipsalliance.diplomacy.nodes.Dangle + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type HalfEdge = _root_.org.chipsalliance.diplomacy.nodes.HalfEdge + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val HalfEdge = _root_.org.chipsalliance.diplomacy.nodes.HalfEdge + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val MonitorsEnabled = _root_.org.chipsalliance.diplomacy.nodes.MonitorsEnabled + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val RenderFlipped = _root_.org.chipsalliance.diplomacy.nodes.RenderFlipped + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val RenderedEdge = _root_.org.chipsalliance.diplomacy.nodes.RenderedEdge + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type RenderedEdge = _root_.org.chipsalliance.diplomacy.nodes.RenderedEdge + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type InwardNodeImp[DI, UI, EI, BI <: Data] = _root_.org.chipsalliance.diplomacy.nodes.InwardNodeImp[DI, UI, EI, BI] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type OutwardNodeImp[DO, UO, EO, BO <: Data] = _root_.org.chipsalliance.diplomacy.nodes.OutwardNodeImp[DO, UO, EO, BO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type NodeImp[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.NodeImp[D, U, EO, EI, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type SimpleNodeImp[D, U, E, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.SimpleNodeImp[D, U, E, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BaseNode = _root_.org.chipsalliance.diplomacy.nodes.BaseNode + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BaseNode = _root_.org.chipsalliance.diplomacy.nodes.BaseNode + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type FormatEdge = _root_.org.chipsalliance.diplomacy.nodes.FormatEdge + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type FormatNode[I <: FormatEdge, O <: FormatEdge] = _root_.org.chipsalliance.diplomacy.nodes.FormatNode[I, O] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type NoHandle = _root_.org.chipsalliance.diplomacy.nodes.NoHandle + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val NoHandleObject = _root_.org.chipsalliance.diplomacy.nodes.NoHandleObject + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type NodeHandle[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] = + _root_.org.chipsalliance.diplomacy.nodes.NodeHandle[DI, UI, EI, BI, DO, UO, EO, BO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val NodeHandle = _root_.org.chipsalliance.diplomacy.nodes.NodeHandle + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type NodeHandlePair[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] = + _root_.org.chipsalliance.diplomacy.nodes.NodeHandlePair[DI, UI, EI, BI, DO, UO, EO, BO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type InwardNodeHandle[DI, UI, EI, BI <: Data] = + _root_.org.chipsalliance.diplomacy.nodes.InwardNodeHandle[DI, UI, EI, BI] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type NodeBinding = _root_.org.chipsalliance.diplomacy.nodes.NodeBinding + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BIND_ONCE = _root_.org.chipsalliance.diplomacy.nodes.BIND_ONCE + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BIND_QUERY = _root_.org.chipsalliance.diplomacy.nodes.BIND_QUERY + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BIND_STAR = _root_.org.chipsalliance.diplomacy.nodes.BIND_STAR + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BIND_FLEX = _root_.org.chipsalliance.diplomacy.nodes.BIND_FLEX + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type InwardNode[DI, UI, BI <: Data] = _root_.org.chipsalliance.diplomacy.nodes.InwardNode[DI, UI, BI] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type OutwardNodeHandle[DO, UO, EO, BO <: Data] = + _root_.org.chipsalliance.diplomacy.nodes.OutwardNodeHandle[DO, UO, EO, BO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type OutwardNode[DO, UO, BO <: Data] = _root_.org.chipsalliance.diplomacy.nodes.OutwardNode[DO, UO, BO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type CycleException = _root_.org.chipsalliance.diplomacy.nodes.CycleException + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type StarCycleException = _root_.org.chipsalliance.diplomacy.nodes.StarCycleException + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type DownwardCycleException = _root_.org.chipsalliance.diplomacy.nodes.DownwardCycleException + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type UpwardCycleException = _root_.org.chipsalliance.diplomacy.nodes.UpwardCycleException + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val Edges = _root_.org.chipsalliance.diplomacy.nodes.Edges + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type Edges[EI, EO] = _root_.org.chipsalliance.diplomacy.nodes.Edges[EI, EO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type MixedCustomNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] = + _root_.org.chipsalliance.diplomacy.nodes.MixedCustomNode[DI, UI, EI, BI, DO, UO, EO, BO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type CustomNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.CustomNode[D, U, EO, EI, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type MixedJunctionNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] = + _root_.org.chipsalliance.diplomacy.nodes.MixedJunctionNode[DI, UI, EI, BI, DO, UO, EO, BO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type JunctionNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.JunctionNode[D, U, EO, EI, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] = + _root_.org.chipsalliance.diplomacy.nodes.MixedAdapterNode[DI, UI, EI, BI, DO, UO, EO, BO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type AdapterNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.AdapterNode[D, U, EO, EI, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type IdentityNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.IdentityNode[D, U, EO, EI, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type EphemeralNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.EphemeralNode[D, U, EO, EI, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type MixedNexusNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] = + _root_.org.chipsalliance.diplomacy.nodes.MixedNexusNode[DI, UI, EI, BI, DO, UO, EO, BO] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type NexusNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.NexusNode[D, U, EO, EI, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type SourceNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.SourceNode[D, U, EO, EI, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type SinkNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.SinkNode[D, U, EO, EI, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type SimpleNodeHandle[D, U, E, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.SimpleNodeHandle[D, U, E, B] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type AnyMixedNode = _root_.org.chipsalliance.diplomacy.nodes.AnyMixedNode - type BundleBridgeInwardNode[T <: Data] = InwardNodeHandle[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T] - type BundleBridgeOutwardNode[T <: Data] = OutwardNodeHandle[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T] - type BundleBridgeNode[T <: Data] = NodeHandle[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T, BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T] +// BundleBridge.scala + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeParams[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeParams[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BundleBridgeParams = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeParams + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeEdgeParams[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeEdgeParams[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeImp[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeImp[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeSink[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeSink[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BundleBridgeSink = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeSink + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeSource[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeSource[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BundleBridgeSource = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeSource + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeIdentityNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeIdentityNode[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BundleBridgeIdentityNode = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeIdentityNode + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeEphemeralNode[T <: Data] = + _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeEphemeralNode[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BundleBridgeEphemeralNode = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeEphemeralNode + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + def BundleBridgeNameNode[T <: Data](name: String) = + _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNameNode[T](name) + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeNexusNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNexusNode[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeNexus[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNexus[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + val BundleBridgeNexus = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNexus + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + def BundleBroadcast[T <: Data]( + name: Option[String] = None, + registered: Boolean = false, + default: Option[() => T] = None, + inputRequiresOutput: Boolean = false, // when false, connecting a source does not mandate connecting a sink + shouldBeInlined: Boolean = true + )( + implicit p: Parameters + ) = _root_.org.chipsalliance.diplomacy.bundlebridge + .BundleBroadcast[T](name, registered, default, inputRequiresOutput, shouldBeInlined)(p) + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeInwardNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeInwardNode[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeOutwardNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeOutwardNode[T] + @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0") + type BundleBridgeNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNode[T] } diff --git a/src/main/scala/util/HeterogeneousBag.scala b/src/main/scala/util/HeterogeneousBag.scala deleted file mode 100644 index f9a591b4b42..00000000000 --- a/src/main/scala/util/HeterogeneousBag.scala +++ /dev/null @@ -1,24 +0,0 @@ -// See LICENSE.SiFive for license details. - -package freechips.rocketchip.util - -import chisel3._ -import chisel3.Record -import chisel3.reflect.DataMirror.internal.chiselTypeClone -import scala.collection.immutable.ListMap - -final case class HeterogeneousBag[T <: Data](elts: Seq[T]) extends Record with collection.IndexedSeq[T] { - def apply(x: Int) = elements(x.toString).asInstanceOf[T] - def length = elts.length - - override def className: String = super.className - val elements = ListMap(elts.zipWithIndex.map { case (n,i) => (i.toString, chiselTypeClone(n)) }:_*) - // IndexedSeq has its own hashCode/equals that we must not use - override def hashCode: Int = super[Record].hashCode - override def equals(that: Any): Boolean = super[Record].equals(that) -} - -object HeterogeneousBag -{ - def fromNode[D <: Data, E](elts: Seq[(D, E)]) = new HeterogeneousBag(elts.map(_._1.cloneType)) -} diff --git a/src/main/scala/util/package.scala b/src/main/scala/util/package.scala index bacaf5b7b17..f960a5049f3 100644 --- a/src/main/scala/util/package.scala +++ b/src/main/scala/util/package.scala @@ -14,7 +14,7 @@ package object util { implicit class UIntIsOneOf(private val x: UInt) extends AnyVal { def isOneOf(s: Seq[UInt]): Bool = s.map(x === _).orR - + def isOneOf(u1: UInt, u2: UInt*): Bool = isOneOf(u1 +: u2.toSeq) } @@ -29,7 +29,7 @@ package object util { // Ignore MSBs of idx val truncIdx = if (idx.isWidthKnown && idx.getWidth <= log2Ceil(x.size)) idx - else (idx | 0.U(log2Ceil(x.size).W))(log2Ceil(x.size)-1, 0) + else (idx | 0.U(log2Ceil(x.size).W))(log2Ceil(x.size) - 1, 0) x.zipWithIndex.tail.foldLeft(x.head) { case (prev, (cur, i)) => Mux(truncIdx === i.U, cur, prev) } } } @@ -44,7 +44,9 @@ package object util { } else { require(isPow2(x.size)) val amt = n.padTo(log2Ceil(x.size)) - (0 until log2Ceil(x.size)).foldLeft(x)((r, i) => (r.rotate(1 << i) zip r).map { case (s, a) => Mux(amt(i), s, a) }) + (0 until log2Ceil(x.size)).foldLeft(x)((r, i) => + (r.rotate(1 << i).zip(r)).map { case (s, a) => Mux(amt(i), s, a) } + ) } } @@ -56,31 +58,34 @@ package object util { } else { require(isPow2(x.size)) val amt = n.padTo(log2Ceil(x.size)) - (0 until log2Ceil(x.size)).foldLeft(x)((r, i) => (r.rotateRight(1 << i) zip r).map { case (s, a) => Mux(amt(i), s, a) }) + (0 until log2Ceil(x.size)).foldLeft(x)((r, i) => + (r.rotateRight(1 << i).zip(r)).map { case (s, a) => Mux(amt(i), s, a) } + ) } } } // allow bitwise ops on Seq[Bool] just like UInt implicit class SeqBoolBitwiseOps(private val x: Seq[Bool]) extends AnyVal { - def & (y: Seq[Bool]): Seq[Bool] = (x zip y).map { case (a, b) => a && b } - def | (y: Seq[Bool]): Seq[Bool] = padZip(x, y).map { case (a, b) => a || b } - def ^ (y: Seq[Bool]): Seq[Bool] = padZip(x, y).map { case (a, b) => a ^ b } - def << (n: Int): Seq[Bool] = Seq.fill(n)(false.B) ++ x - def >> (n: Int): Seq[Bool] = x drop n + def &(y: Seq[Bool]): Seq[Bool] = (x.zip(y)).map { case (a, b) => a && b } + def |(y: Seq[Bool]): Seq[Bool] = padZip(x, y).map { case (a, b) => a || b } + def ^(y: Seq[Bool]): Seq[Bool] = padZip(x, y).map { case (a, b) => a ^ b } + def <<(n: Int): Seq[Bool] = Seq.fill(n)(false.B) ++ x + def >>(n: Int): Seq[Bool] = x.drop(n) def unary_~ : Seq[Bool] = x.map(!_) - def andR: Bool = if (x.isEmpty) true.B else x.reduce(_&&_) - def orR: Bool = if (x.isEmpty) false.B else x.reduce(_||_) - def xorR: Bool = if (x.isEmpty) false.B else x.reduce(_^_) + def andR: Bool = if (x.isEmpty) true.B else x.reduce(_ && _) + def orR: Bool = if (x.isEmpty) false.B else x.reduce(_ || _) + def xorR: Bool = if (x.isEmpty) false.B else x.reduce(_ ^ _) - private def padZip(y: Seq[Bool], z: Seq[Bool]): Seq[(Bool, Bool)] = y.padTo(z.size, false.B) zip z.padTo(y.size, false.B) + private def padZip(y: Seq[Bool], z: Seq[Bool]): Seq[(Bool, Bool)] = + y.padTo(z.size, false.B).zip(z.padTo(y.size, false.B)) } implicit class DataToAugmentedData[T <: Data](private val x: T) extends AnyVal { def holdUnless(enable: Bool): T = Mux(enable, x, RegEnable(x, enable)) def getElements: Seq[Element] = x match { - case e: Element => Seq(e) + case e: Element => Seq(e) case a: Aggregate => a.getElements.flatMap(_.getElements) } } @@ -89,39 +94,40 @@ package object util { type DataCanBeValid = Data { val valid: Bool } implicit class SeqMemToAugmentedSeqMem[T <: Data](private val x: SyncReadMem[T]) extends AnyVal { - def readAndHold(addr: UInt, enable: Bool): T = x.read(addr, enable) holdUnless RegNext(enable) + def readAndHold(addr: UInt, enable: Bool): T = x.read(addr, enable).holdUnless(RegNext(enable)) } implicit class StringToAugmentedString(private val x: String) extends AnyVal { + /** converts from camel case to to underscores, also removing all spaces */ - def underscore: String = x.tail.foldLeft(x.headOption.map(_.toLower + "") getOrElse "") { + def underscore: String = x.tail.foldLeft(x.headOption.map(_.toLower + "").getOrElse("")) { case (acc, c) if c.isUpper => acc + "_" + c.toLower - case (acc, c) if c == ' ' => acc - case (acc, c) => acc + c + case (acc, c) if c == ' ' => acc + case (acc, c) => acc + c } /** converts spaces or underscores to hyphens, also lowering case */ - def kebab: String = x.toLowerCase map { + def kebab: String = x.toLowerCase.map { case ' ' => '-' case '_' => '-' - case c => c + case c => c } def named(name: Option[String]): String = { - x + name.map("_named_" + _ ).getOrElse("_with_no_name") + x + name.map("_named_" + _).getOrElse("_with_no_name") } def named(name: String): String = named(Some(name)) } - implicit def uintToBitPat(x: UInt): BitPat = BitPat(x) - implicit def wcToUInt(c: WideCounter): UInt = c.value + implicit def uintToBitPat(x: UInt): BitPat = BitPat(x) + implicit def wcToUInt(c: WideCounter): UInt = c.value implicit class UIntToAugmentedUInt(private val x: UInt) extends AnyVal { def sextTo(n: Int): UInt = { require(x.getWidth <= n) if (x.getWidth == n) x - else Cat(Fill(n - x.getWidth, x(x.getWidth-1)), x) + else Cat(Fill(n - x.getWidth, x(x.getWidth - 1)), x) } def padTo(n: Int): UInt = { @@ -131,41 +137,41 @@ package object util { } // shifts left by n if n >= 0, or right by -n if n < 0 - def << (n: SInt): UInt = { + def <<(n: SInt): UInt = { val w = n.getWidth - 1 require(w <= 30) - val shifted = x << n(w-1, 0) + val shifted = x << n(w - 1, 0) Mux(n(w), shifted >> (1 << w), shifted) } // shifts right by n if n >= 0, or left by -n if n < 0 - def >> (n: SInt): UInt = { + def >>(n: SInt): UInt = { val w = n.getWidth - 1 require(w <= 30) - val shifted = x << (1 << w) >> n(w-1, 0) + val shifted = x << (1 << w) >> n(w - 1, 0) Mux(n(w), shifted, shifted >> (1 << w)) } // Like UInt.apply(hi, lo), but returns 0.U for zero-width extracts def extract(hi: Int, lo: Int): UInt = { - require(hi >= lo-1) - if (hi == lo-1) 0.U + require(hi >= lo - 1) + if (hi == lo - 1) 0.U else x(hi, lo) } // Like Some(UInt.apply(hi, lo)), but returns None for zero-width extracts def extractOption(hi: Int, lo: Int): Option[UInt] = { - require(hi >= lo-1) - if (hi == lo-1) None + require(hi >= lo - 1) + if (hi == lo - 1) None else Some(x(hi, lo)) } // like x & ~y, but first truncate or zero-extend y to x's width def andNot(y: UInt): UInt = x & ~(y | (x & 0.U)) - def rotateRight(n: Int): UInt = if (n == 0) x else Cat(x(n-1, 0), x >> n) + def rotateRight(n: Int): UInt = if (n == 0) x else Cat(x(n - 1, 0), x >> n) def rotateRight(n: UInt): UInt = { if (x.getWidth <= 1) { @@ -176,7 +182,7 @@ package object util { } } - def rotateLeft(n: Int): UInt = if (n == 0) x else Cat(x(x.getWidth-1-n,0), x(x.getWidth-1,x.getWidth-n)) + def rotateLeft(n: Int): UInt = if (n == 0) x else Cat(x(x.getWidth - 1 - n, 0), x(x.getWidth - 1, x.getWidth - n)) def rotateLeft(n: UInt): UInt = { if (x.getWidth <= 1) { @@ -190,29 +196,28 @@ package object util { // compute (this + y) % n, given (this < n) and (y < n) def addWrap(y: UInt, n: Int): UInt = { val z = x +& y - if (isPow2(n)) z(n.log2-1, 0) else Mux(z >= n.U, z - n.U, z)(log2Ceil(n)-1, 0) + if (isPow2(n)) z(n.log2 - 1, 0) else Mux(z >= n.U, z - n.U, z)(log2Ceil(n) - 1, 0) } // compute (this - y) % n, given (this < n) and (y < n) def subWrap(y: UInt, n: Int): UInt = { val z = x -& y - if (isPow2(n)) z(n.log2-1, 0) else Mux(z(z.getWidth-1), z + n.U, z)(log2Ceil(n)-1, 0) + if (isPow2(n)) z(n.log2 - 1, 0) else Mux(z(z.getWidth - 1), z + n.U, z)(log2Ceil(n) - 1, 0) } - def grouped(width: Int): Seq[UInt] = - (0 until x.getWidth by width).map(base => x(base + width - 1, base)) + def grouped(width: Int): Seq[UInt] = (0 until x.getWidth by width).map(base => x(base + width - 1, base)) def inRange(base: UInt, bounds: UInt) = x >= base && x < bounds - def ## (y: Option[UInt]): UInt = y.map(x ## _).getOrElse(x) + def ##(y: Option[UInt]): UInt = y.map(x ## _).getOrElse(x) // Like >=, but prevents x-prop for ('x >= 0) - def >== (y: UInt): Bool = x >= y || y === 0.U + def >==(y: UInt): Bool = x >= y || y === 0.U } implicit class OptionUIntToAugmentedOptionUInt(private val x: Option[UInt]) extends AnyVal { - def ## (y: UInt): UInt = x.map(_ ## y).getOrElse(y) - def ## (y: Option[UInt]): Option[UInt] = x.map(_ ## y) + def ##(y: UInt): UInt = x.map(_ ## y).getOrElse(y) + def ##(y: Option[UInt]): Option[UInt] = x.map(_ ## y) } implicit class BooleanToAugmentedBoolean(private val x: Boolean) extends AnyVal { @@ -230,9 +235,9 @@ package object util { } } - def OH1ToOH(x: UInt): UInt = (x << 1 | 1.U) & ~Cat(0.U(1.W), x) + def OH1ToOH(x: UInt): UInt = (x << 1 | 1.U) & ~Cat(0.U(1.W), x) def OH1ToUInt(x: UInt): UInt = OHToUInt(OH1ToOH(x)) - def UIntToOH1(x: UInt, width: Int): UInt = ~((-1).S(width.W).asUInt << x)(width-1, 0) + def UIntToOH1(x: UInt, width: Int): UInt = ~((-1).S(width.W).asUInt << x)(width - 1, 0) def UIntToOH1(x: UInt): UInt = UIntToOH1(x, (1 << x.getWidth) - 1) def trailingZeros(x: Int): Option[Int] = if (x > 0) Some(log2Ceil(x & -x)) else None @@ -241,23 +246,21 @@ package object util { def leftOR(x: UInt): UInt = leftOR(x, x.getWidth, x.getWidth) def leftOR(x: UInt, width: Integer, cap: Integer = 999999): UInt = { val stop = min(width, cap) - def helper(s: Int, x: UInt): UInt = - if (s >= stop) x else helper(s+s, x | (x << s)(width-1,0)) - helper(1, x)(width-1, 0) + def helper(s: Int, x: UInt): UInt = if (s >= stop) x else helper(s + s, x | (x << s)(width - 1, 0)) + helper(1, x)(width - 1, 0) } // Fill 1s form high bits to low bits def rightOR(x: UInt): UInt = rightOR(x, x.getWidth, x.getWidth) def rightOR(x: UInt, width: Integer, cap: Integer = 999999): UInt = { val stop = min(width, cap) - def helper(s: Int, x: UInt): UInt = - if (s >= stop) x else helper(s+s, x | (x >> s)) - helper(1, x)(width-1, 0) + def helper(s: Int, x: UInt): UInt = if (s >= stop) x else helper(s + s, x | (x >> s)) + helper(1, x)(width - 1, 0) } def OptimizationBarrier[T <: Data](in: T): T = { val barrier = Module(new Module { - val io = IO(new Bundle { + val io = IO(new Bundle { val x = Input(chiselTypeOf(in)) val y = Output(chiselTypeOf(in)) }) @@ -268,22 +271,27 @@ package object util { barrier.io.y } - /** Similar to Seq.groupBy except this returns a Seq instead of a Map - * Useful for deterministic code generation + /** Similar to Seq.groupBy except this returns a Seq instead of a Map Useful for deterministic code generation */ def groupByIntoSeq[A, K](xs: Seq[A])(f: A => K): immutable.Seq[(K, immutable.Seq[A])] = { val map = mutable.LinkedHashMap.empty[K, mutable.ListBuffer[A]] for (x <- xs) { val key = f(x) - val l = map.getOrElseUpdate(key, mutable.ListBuffer.empty[A]) + val l = map.getOrElseUpdate(key, mutable.ListBuffer.empty[A]) l += x } map.view.map({ case (k, vs) => k -> vs.toList }).toList } def heterogeneousOrGlobalSetting[T](in: Seq[T], n: Int): Seq[T] = in.size match { - case 1 => List.fill(n)(in.head) + case 1 => List.fill(n)(in.head) case x if x == n => in - case _ => throw new Exception(s"must provide exactly 1 or $n of some field, but got:\n$in") + case _ => throw new Exception(s"must provide exactly 1 or $n of some field, but got:\n$in") } + + // HeterogeneousBag moved to standalond diplomacy + @deprecated("HeterogeneousBag has been absorbed into standalone diplomacy library", "rocketchip 2.0.0") + def HeterogeneousBag[T <: Data](elts: Seq[T]) = _root_.org.chipsalliance.diplomacy.nodes.HeterogeneousBag[T](elts) + @deprecated("HeterogeneousBag has been absorbed into standalone diplomacy library", "rocketchip 2.0.0") + val HeterogeneousBag = _root_.org.chipsalliance.diplomacy.nodes.HeterogeneousBag }