From fa6456848e95663c91e095fbdf7095f848ab36c8 Mon Sep 17 00:00:00 2001 From: Deborah Soung Date: Mon, 16 Mar 2020 11:23:57 -0700 Subject: [PATCH] Restoring staged generator PRs (Reverting #2329) This reverts commit e170f8f8a21ebe8a9e04aed47c2644c06e4a442e. --- Makefrag | 9 +- README.md | 67 ++++++--- build.sbt | 5 +- emulator/Makefrag-verilator | 4 +- regression/Makefile | 40 ++--- src/main/scala/groundtest/Generator.scala | 10 +- .../scala/stage/RocketChipAnnotations.scala | 52 +++++++ src/main/scala/stage/RocketChipCli.scala | 17 +++ src/main/scala/stage/RocketChipOptions.scala | 41 +++++ src/main/scala/stage/package.scala | 24 +++ .../scala/stage/phases/AddDefaultTests.scala | 140 ++++++++++++++++++ src/main/scala/stage/phases/Checks.scala | 47 ++++++ .../stage/phases/GenerateArtefacts.scala | 27 ++++ .../stage/phases/GenerateFirrtlAnnos.scala | 42 ++++++ .../scala/stage/phases/GenerateROMs.scala | 31 ++++ .../phases/GenerateTestSuiteMakefrags.scala | 33 +++++ .../scala/stage/phases/PreElaboration.scala | 39 +++++ .../stage/phases/TransformAnnotations.scala | 23 +++ src/main/scala/system/Generator.scala | 111 -------------- .../system/RocketChipStageGenerator.scala | 35 +++++ src/main/scala/system/RocketTestSuite.scala | 26 ++-- src/main/scala/unittest/Generator.scala | 10 +- src/main/scala/util/GeneratorUtils.scala | 114 +------------- .../generatorTests/StageGeneratorSpec.scala | 44 ++++++ vsim/Makefrag | 4 +- vsim/Makefrag-verilog | 2 +- 26 files changed, 698 insertions(+), 299 deletions(-) create mode 100644 src/main/scala/stage/RocketChipAnnotations.scala create mode 100644 src/main/scala/stage/RocketChipCli.scala create mode 100644 src/main/scala/stage/RocketChipOptions.scala create mode 100644 src/main/scala/stage/package.scala create mode 100644 src/main/scala/stage/phases/AddDefaultTests.scala create mode 100644 src/main/scala/stage/phases/Checks.scala create mode 100644 src/main/scala/stage/phases/GenerateArtefacts.scala create mode 100644 src/main/scala/stage/phases/GenerateFirrtlAnnos.scala create mode 100644 src/main/scala/stage/phases/GenerateROMs.scala create mode 100644 src/main/scala/stage/phases/GenerateTestSuiteMakefrags.scala create mode 100644 src/main/scala/stage/phases/PreElaboration.scala create mode 100644 src/main/scala/stage/phases/TransformAnnotations.scala delete mode 100644 src/main/scala/system/Generator.scala create mode 100644 src/main/scala/system/RocketChipStageGenerator.scala create mode 100644 src/test/scala/generatorTests/StageGeneratorSpec.scala diff --git a/Makefrag b/Makefrag index f1d8d8efa2e..d4b65209254 100644 --- a/Makefrag +++ b/Makefrag @@ -6,9 +6,14 @@ endif MODEL ?= TestHarness PROJECT ?= freechips.rocketchip.system CFG_PROJECT ?= $(PROJECT) -CONFIG ?= DefaultConfig +CONFIG ?= $(CFG_PROJECT).DefaultConfig # TODO: For now must match rocketchip.Generator -long_name = $(PROJECT).$(CONFIG) +comma := , +space := $() $() +splitConfigs := $(subst $(comma), ,$(CONFIG)) +configBases := $(foreach config,$(splitConfigs),$(lastword $(subst ., ,$(config)))) +CONFIG_STR := $(subst $(space),_,$(configBases)) +long_name = $(PROJECT).$(CONFIG_STR) VLSI_MEM_GEN ?= $(base_dir)/scripts/vlsi_mem_gen diff --git a/README.md b/README.md index 7cc69911c9b..f5486623539 100644 --- a/README.md +++ b/README.md @@ -284,14 +284,25 @@ Chisel generated Verilog code and its associated C++ code generated by Verilator. $ ls $ROCKETCHIP/emulator/generated-src - DefaultConfig.dts - DefaultConfig.graphml - DefaultConfig.json - DefaultConfig.memmap.json freechips.rocketchip.system.DefaultConfig + freechips.rocketchip.system.DefaultConfig.0x0.0.regmap.json + freechips.rocketchip.system.DefaultConfig.0x0.1.regmap.json + freechips.rocketchip.system.DefaultConfig.0x2000000.0.regmap.json + freechips.rocketchip.system.DefaultConfig.0x40.0.regmap.json + freechips.rocketchip.system.DefaultConfig.0xc000000.0.regmap.json + freechips.rocketchip.system.DefaultConfig.anno.json + freechips.rocketchip.system.DefaultConfig.behav_srams.v + freechips.rocketchip.system.DefaultConfig.conf freechips.rocketchip.system.DefaultConfig.d + freechips.rocketchip.system.DefaultConfig.dts freechips.rocketchip.system.DefaultConfig.fir + freechips.rocketchip.system.DefaultConfig.graphml + freechips.rocketchip.system.DefaultConfig.json + freechips.rocketchip.system.DefaultConfig.memmap.json + freechips.rocketchip.system.DefaultConfig.plusArgs + freechips.rocketchip.system.DefaultConfig.rom.conf freechips.rocketchip.system.DefaultConfig.v + TestHarness.anno.json $ ls $ROCKETCHIP/emulator/generated-src/freechips.rocketchip.system.DefaultConfig VTestHarness__1.cpp VTestHarness__2.cpp @@ -323,7 +334,7 @@ writeback stage, perhaps, because of a instruction cache miss at PC You can generate synthesizable Verilog with the following commands: $ cd $ROCKETCHIP/vsim - $ make verilog CONFIG=DefaultFPGAConfig + $ make verilog CONFIG=freechips.rocketchip.system.DefaultFPGAConfig The Verilog used for the FPGA tools will be generated in vsim/generated-src. Please proceed further with the directions shown in @@ -337,7 +348,7 @@ tests and benchmarks in simulation with the following commands (again assuming you have N cores on your host machine): $ cd $ROCKETCHIP/vsim - $ make -jN run CONFIG=DefaultFPGAConfig + $ make -jN run CONFIG=freechips.rocketchip.system.DefaultFPGAConfig The generated output looks similar to those generated from the emulator. Look into vsim/output/\*.out for the output of the executed assembly @@ -354,15 +365,25 @@ Now take a look at vsim/generated-src, and the contents of the Top.DefaultConfig.conf file: $ cd $ROCKETCHIP/vsim/generated-src - DefaultConfig.dts - DefaultConfig.graphml - DefaultConfig.json - DefaultConfig.memmap.json + freechips.rocketchip.system.DefaultConfig + freechips.rocketchip.system.DefaultConfig.0x0.0.regmap.json + freechips.rocketchip.system.DefaultConfig.0x0.1.regmap.json + freechips.rocketchip.system.DefaultConfig.0x2000000.0.regmap.json + freechips.rocketchip.system.DefaultConfig.0x40.0.regmap.json + freechips.rocketchip.system.DefaultConfig.0xc000000.0.regmap.json + freechips.rocketchip.system.DefaultConfig.anno.json freechips.rocketchip.system.DefaultConfig.behav_srams.v freechips.rocketchip.system.DefaultConfig.conf freechips.rocketchip.system.DefaultConfig.d + freechips.rocketchip.system.DefaultConfig.dts freechips.rocketchip.system.DefaultConfig.fir + freechips.rocketchip.system.DefaultConfig.graphml + freechips.rocketchip.system.DefaultConfig.json + freechips.rocketchip.system.DefaultConfig.memmap.json + freechips.rocketchip.system.DefaultConfig.plusArgs + freechips.rocketchip.system.DefaultConfig.rom.conf freechips.rocketchip.system.DefaultConfig.v + TestHarness.anno.json $ cat $ROCKETCHIP/vsim/generated-src/*.conf name data_arrays_0_ext depth 512 width 256 ports mrw mask_gran 8 name tag_array_ext depth 64 width 88 ports mrw mask_gran 22 @@ -395,26 +416,26 @@ tests and benchmarks. ## How can I parameterize my Rocket chip? By now, you probably figured out that all generated files have a configuration -name attached, e.g. DefaultConfig. Take a look at -src/main/scala/system/Configs.scala. Search for NSets and NWays defined in -BaseConfig. You can change those numbers to get a Rocket core with different +name attached, e.g. `freechips.rocketchip.system.DefaultConfig`. Take a look at +`src/main/scala/system/Configs.scala`. Search for `NSets` and `NWays` defined in +`BaseConfig`. You can change those numbers to get a Rocket core with different cache parameters. For example, by changing L1I, NWays to 4, you will get a 32KB 4-way set-associative L1 instruction cache rather than a 16KB 2-way set-associative L1 instruction cache. -Towards the end, you can also find that DefaultSmallConfig inherits all -parameters from BaseConfig but overrides the same parameters of -WithNSmallCores. +Towards the end, you can also find that `DefaultSmallConfig` inherits all +parameters from `BaseConfig` but overrides the same parameters of +`WithNSmallCores`. -Now take a look at vsim/Makefile. Search for the CONFIG variable. -By default, it is set to DefaultConfig. You can also change the +Now take a look at `vsim/Makefile`. Search for the `CONFIG` variable. +By default, it is set to `freechips.rocketchip.system.DefaultConfig`. You can also change the CONFIG variable on the make command line: $ cd $ROCKETCHIP/vsim - $ make -jN CONFIG=DefaultSmallConfig run-asm-tests + $ make -jN CONFIG=freechips.rocketchip.system.DefaultSmallConfig run-asm-tests Or, even by defining CONFIG as an environment variable: - $ export CONFIG=DefaultSmallConfig + $ export CONFIG=freechips.rocketchip.system.DefaultSmallConfig $ make -jN run-asm-tests This parameterization is one of the many strengths of processor @@ -431,7 +452,7 @@ you can create your own Configuration(s) and compose them with Config's ++ opera } class MyConfig extends Config (new WithNExtInterrupts(16) ++ new DefaultSmallConfig) -Then you can build as usual with CONFIG=MyConfig. +Then you can build as usual with `CONFIG=.MyConfig`. ## Debugging with GDB @@ -450,11 +471,11 @@ For that we need to add a Remote Bit-Bang client to the emulator. We can do so b To build the emulator with `DefaultConfigRBB` configuration we use the command: rocket-chip$ cd emulator - emulator$ CONFIG=DefaultConfigRBB make + emulator$ CONFIG=freechips.rocketchip.system.DefaultConfigRBB make We can also build a debug version capable of generating VCD waveforms using the command: - emulator$ CONFIG=DefaultConfigRBB make debug + emulator$ CONFIG=freechips.rocketchip.system.DefaultConfigRBB make debug By default the emulator is generated under the name `emulator-freechips.rocketchip.system-DefaultConfigRBB` in the first case and `emulator-freechips.rocketchip.system-DefaultConfigRBB-debug` in the second. diff --git a/build.sbt b/build.sbt index dd06845b7dc..dc204983cad 100644 --- a/build.sbt +++ b/build.sbt @@ -1,9 +1,7 @@ // See LICENSE.Berkeley for license details. -import sbt.complete._ import sbt.complete.DefaultParsers._ -import xerial.sbt.pack._ -import sys.process._ +import scala.sys.process._ enablePlugins(PackPlugin) @@ -16,6 +14,7 @@ lazy val commonSettings = Seq( scalacOptions ++= Seq("-deprecation","-unchecked","-Xsource:2.11"), libraryDependencies ++= Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value), libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.6.1"), + libraryDependencies ++= Seq("org.scalatest" %% "scalatest" % "3.0.8" % "test"), addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full), resolvers ++= Seq( Resolver.sonatypeRepo("snapshots"), diff --git a/emulator/Makefrag-verilator b/emulator/Makefrag-verilator index d6423ada0ad..8011a42aef6 100644 --- a/emulator/Makefrag-verilator +++ b/emulator/Makefrag-verilator @@ -10,7 +10,7 @@ verilog = \ $(generated_dir)/%.fir $(generated_dir)/%.d: $(FIRRTL_JAR) $(chisel_srcs) $(bootrom_img) mkdir -p $(dir $@) - cd $(base_dir) && $(SBT) "runMain $(PROJECT).Generator $(generated_dir) $(PROJECT) $(MODEL) $(CFG_PROJECT) $(CONFIG)" + cd $(base_dir) && $(SBT) "runMain $(PROJECT).Generator -td $(generated_dir) -T $(PROJECT).$(MODEL) -C $(CONFIG)" %.v %.conf: %.fir $(FIRRTL_JAR) mkdir -p $(dir $@) @@ -69,7 +69,7 @@ VERILATOR_FLAGS := --top-module $(MODEL) \ --threads $(VERILATOR_THREADS) -Wno-UNOPTTHREADS \ -Wno-STMTDLY --x-assign unique \ -I$(vsrc) \ - -O3 -CFLAGS "$(CXXFLAGS) -DVERILATOR -DTEST_HARNESS=V$(MODEL) -include $(csrc)/verilator.h -include $(generated_dir)/$(PROJECT).$(CONFIG).plusArgs" + -O3 -CFLAGS "$(CXXFLAGS) -DVERILATOR -DTEST_HARNESS=V$(MODEL) -include $(csrc)/verilator.h -include $(generated_dir)/$(long_name).plusArgs" cppfiles = $(addprefix $(csrc)/, $(addsuffix .cc, $(CXXSRCS))) headers = $(wildcard $(csrc)/*.h) diff --git a/regression/Makefile b/regression/Makefile index 67983ad9e7f..3b660c9ccd5 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -46,22 +46,22 @@ endif ifeq ($(SUITE),RocketSuiteA) PROJECT=freechips.rocketchip.system -CONFIGS=DefaultConfig +CONFIGS=$(PROJECT).DefaultConfig endif ifeq ($(SUITE),RocketSuiteB) PROJECT=freechips.rocketchip.system -CONFIGS=DefaultBufferlessConfig +CONFIGS=$(PROJECT).DefaultBufferlessConfig endif ifeq ($(SUITE),RocketSuiteC) PROJECT=freechips.rocketchip.system -CONFIGS=TinyConfig +CONFIGS=$(PROJECT).TinyConfig endif ifeq ($(SUITE),UnittestSuite) PROJECT=freechips.rocketchip.unittest -CONFIGS=AMBAUnitTestConfig TLSimpleUnitTestConfig TLWidthUnitTestConfig +CONFIGS=$(PROJECT).AMBAUnitTestConfig $(PROJECT).TLSimpleUnitTestConfig $(PROJECT).TLWidthUnitTestConfig endif ifeq ($(SUITE), JtagDtmSuite) @@ -69,13 +69,13 @@ PROJECT=freechips.rocketchip.system export JTAG_DTM_ENABLE_SBA ?= off ifeq ($(JTAG_DTM_ENABLE_SBA), off) -CONFIGS_32=WithJtagDTMSystem_DefaultRV32Config -CONFIGS_64=WithJtagDTMSystem_DefaultConfig +CONFIGS_32=$(PROJECT).WithJtagDTMSystem,$(PROJECT).DefaultRV32Config +CONFIGS_64=$(PROJECT).WithJtagDTMSystem,$(PROJECT).DefaultConfig endif ifeq ($(JTAG_DTM_ENABLE_SBA), on) -CONFIGS_32=WithJtagDTMSystem_WithDebugSBASystem_DefaultRV32Config -CONFIGS_64=WithJtagDTMSystem_WithDebugSBASystem_DefaultConfig +CONFIGS_32=$(PROJECT).WithJtagDTMSystem,$(PROJECT).WithDebugSBASystem,$(PROJECT).DefaultRV32Config +CONFIGS_64=$(PROJECT).WithJtagDTMSystem,$(PROJECT).WithDebugSBASystem,$(PROJECT).DefaultConfig endif CONFIGS += $(CONFIGS_32) @@ -89,18 +89,18 @@ endif ifeq ($(SUITE), Miscellaneous) PROJECT=freechips.rocketchip.system CONFIGS=\ - DefaultSmallConfig \ - DualBankConfig \ - DualChannelConfig \ - DualChannelDualBankConfig \ - RoccExampleConfig \ - Edge128BitConfig \ - Edge32BitConfig \ - QuadChannelBenchmarkConfig \ - EightChannelConfig \ - DualCoreConfig \ - MemPortOnlyConfig \ - MMIOPortOnlyConfig + $(PROJECT).DefaultSmallConfig \ + $(PROJECT).DualBankConfig \ + $(PROJECT).DualChannelConfig \ + $(PROJECT).DualChannelDualBankConfig \ + $(PROJECT).RoccExampleConfig \ + $(PROJECT).Edge128BitConfig \ + $(PROJECT).Edge32BitConfig \ + $(PROJECT).QuadChannelBenchmarkConfig \ + $(PROJECT).EightChannelConfig \ + $(PROJECT).DualCoreConfig \ + $(PROJECT).MemPortOnlyConfig \ + $(PROJECT).MMIOPortOnlyConfig endif # These are the named regression targets. While it's expected you run them in diff --git a/src/main/scala/groundtest/Generator.scala b/src/main/scala/groundtest/Generator.scala index b3ffeb8616b..6279c67b4e3 100644 --- a/src/main/scala/groundtest/Generator.scala +++ b/src/main/scala/groundtest/Generator.scala @@ -2,11 +2,7 @@ package freechips.rocketchip.groundtest -import freechips.rocketchip.util.GeneratorApp +import firrtl.options.StageMain +import freechips.rocketchip.system.RocketChipStage -object Generator extends GeneratorApp { - generateFirrtl - generateAnno - generateTestSuiteMakefrags // TODO: Needed only for legacy make targets - generateArtefacts -} +object Generator extends StageMain(new RocketChipStage) diff --git a/src/main/scala/stage/RocketChipAnnotations.scala b/src/main/scala/stage/RocketChipAnnotations.scala new file mode 100644 index 00000000000..f0c2c1302cf --- /dev/null +++ b/src/main/scala/stage/RocketChipAnnotations.scala @@ -0,0 +1,52 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage + +import chisel3.experimental.BaseModule +import firrtl.annotations.{Annotation, NoTargetAnnotation} +import firrtl.options.{HasShellOptions, ShellOption, Unserializable} + +sealed trait RocketChipOption extends Unserializable { this: Annotation => } + +/* required options */ + +/** Path to top module class */ +case class TopModuleAnnotation(clazz: Class[_ <: Any]) extends NoTargetAnnotation with RocketChipOption +private[stage] object TopModuleAnnotation extends HasShellOptions { + override val options = Seq( + new ShellOption[String]( + longOption = "top-module", + toAnnotationSeq = a => Seq(TopModuleAnnotation(Class.forName(a).asInstanceOf[Class[_ <: BaseModule]])), + helpText = "", + shortOption = Some("T") + ) + ) +} + +/** Paths to config classes */ +case class ConfigsAnnotation(configNames: Seq[String]) extends NoTargetAnnotation with RocketChipOption +private[stage] object ConfigsAnnotation extends HasShellOptions { + override val options = Seq( + new ShellOption[Seq[String]]( + longOption = "configs", + toAnnotationSeq = a => Seq(ConfigsAnnotation(a)), + helpText = "", + shortOption = Some("C") + ) + ) +} + +/* optional options */ + +/** Optional base name for generated files' filenames */ +case class OutputBaseNameAnnotation(outputBaseName: String) extends NoTargetAnnotation with RocketChipOption +private[stage] object OutputBaseNameAnnotation extends HasShellOptions { + override val options = Seq( + new ShellOption[String]( + longOption = "name", + toAnnotationSeq = a => Seq(OutputBaseNameAnnotation(a)), + helpText = "", + shortOption = Some("n") + ) + ) +} diff --git a/src/main/scala/stage/RocketChipCli.scala b/src/main/scala/stage/RocketChipCli.scala new file mode 100644 index 00000000000..30becb6ceeb --- /dev/null +++ b/src/main/scala/stage/RocketChipCli.scala @@ -0,0 +1,17 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage + +import firrtl.options.Shell + +trait RocketChipCli { this: Shell => + + parser.note("Rocket Chip Compiler Options") + Seq( + TopModuleAnnotation, + ConfigsAnnotation, + OutputBaseNameAnnotation, + ) + .foreach(_.addOptions(parser)) + +} diff --git a/src/main/scala/stage/RocketChipOptions.scala b/src/main/scala/stage/RocketChipOptions.scala new file mode 100644 index 00000000000..2fac6a276ff --- /dev/null +++ b/src/main/scala/stage/RocketChipOptions.scala @@ -0,0 +1,41 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage + +class RocketChipOptions private[stage] ( + val topModule: Option[Class[_ <: Any]] = None, + val configNames: Option[Seq[String]] = None, + val outputBaseName: Option[String] = None) { + + private[stage] def copy( + topModule: Option[Class[_ <: Any]] = topModule, + configNames: Option[Seq[String]] = configNames, + outputBaseName: Option[String] = outputBaseName, + ): RocketChipOptions = { + + new RocketChipOptions( + topModule=topModule, + configNames=configNames, + outputBaseName=outputBaseName, + ) + } + + lazy val topPackage: Option[String] = topModule match { + case Some(a) => Some(a.getPackage.getName) + case _ => None + } + + lazy val configClass: Option[String] = configNames match { + case Some(names) => + val classNames = names.map{ n => n.split('.').last } + Some(classNames.mkString("_")) + case _ => None + } + + lazy val longName: Option[String] = outputBaseName match { + case Some(name) => Some(name) + case _ => + if (!topPackage.isEmpty && !configClass.isEmpty) Some(s"${topPackage.get}.${configClass.get}") else None + } +} + diff --git a/src/main/scala/stage/package.scala b/src/main/scala/stage/package.scala new file mode 100644 index 00000000000..db5b42234d1 --- /dev/null +++ b/src/main/scala/stage/package.scala @@ -0,0 +1,24 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip + +import firrtl.AnnotationSeq +import firrtl.options.OptionsView + +package object stage { + + implicit object RocketChipOptionsView extends OptionsView[RocketChipOptions] { + + def view(annotations: AnnotationSeq): RocketChipOptions = annotations + .collect { case a: RocketChipOption => a } + .foldLeft(new RocketChipOptions()){ (c, x) => + x match { + case TopModuleAnnotation(a) => c.copy(topModule = Some(a)) + case ConfigsAnnotation(a) => c.copy(configNames = Some(a)) + case OutputBaseNameAnnotation(a) => c.copy(outputBaseName = Some(a)) + } + } + + } + +} diff --git a/src/main/scala/stage/phases/AddDefaultTests.scala b/src/main/scala/stage/phases/AddDefaultTests.scala new file mode 100644 index 00000000000..1fdd8b9a44a --- /dev/null +++ b/src/main/scala/stage/phases/AddDefaultTests.scala @@ -0,0 +1,140 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage.phases + + +import chipsalliance.rocketchip.config.Parameters +import chisel3.stage.phases.Elaborate +import firrtl.AnnotationSeq +import firrtl.annotations.NoTargetAnnotation +import firrtl.options.{Phase, PreservesAll} +import firrtl.options.Viewer.view +import freechips.rocketchip.stage.RocketChipOptions +import freechips.rocketchip.subsystem.RocketTilesKey +import freechips.rocketchip.system.{DefaultTestSuites, RegressionTestSuite, RocketTestSuite, TestGeneration} +import freechips.rocketchip.tile.XLen +import freechips.rocketchip.util.HasRocketChipStageUtils +import freechips.rocketchip.system.DefaultTestSuites._ + +import scala.collection.mutable + +/** Annotation that contains a list of [[RocketTestSuite]]s to run */ +case class RocketTestSuiteAnnotation(tests: Seq[RocketTestSuite]) extends NoTargetAnnotation + +/** Generates [[RocketTestSuiteAnnotation]] depending on whether the top-module project is part of + * [[freechips.rocketchip.system]] or not (e.g. for unit tests). + */ +class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils { + + override val prerequisites = Seq(classOf[Checks], classOf[Elaborate]) + override val dependents = Seq(classOf[GenerateTestSuiteMakefrags]) + + def GenerateDefaultTestSuites(): List[RocketTestSuite] = { + List(DefaultTestSuites.groundtest64("p"), DefaultTestSuites.emptyBmarks, DefaultTestSuites.singleRegression) + } + + def GenerateSystemTestSuites(annotations: AnnotationSeq): scala.collection.mutable.Buffer[RocketTestSuite] = { + val params: Parameters = getConfig(view[RocketChipOptions](annotations).configNames.get).toInstance + val xlen = params(XLen) + val tests = scala.collection.mutable.Buffer[RocketTestSuite]() + + val regressionTests = mutable.LinkedHashSet( + "rv64ud-v-fcvt", + "rv64ud-p-fdiv", + "rv64ud-v-fadd", + "rv64uf-v-fadd", + "rv64um-v-mul", + "rv64mi-p-breakpoint", + "rv64uc-v-rvc", + "rv64ud-v-structural", + "rv64si-p-wfi", + "rv64um-v-divw", + "rv64ua-v-lrsc", + "rv64ui-v-fence_i", + "rv64ud-v-fcvt_w", + "rv64uf-v-fmin", + "rv64ui-v-sb", + "rv64ua-v-amomax_d", + "rv64ud-v-move", + "rv64ud-v-fclass", + "rv64ua-v-amoand_d", + "rv64ua-v-amoxor_d", + "rv64si-p-sbreak", + "rv64ud-v-fmadd", + "rv64uf-v-ldst", + "rv64um-v-mulh", + "rv64si-p-dirty", + "rv32mi-p-ma_addr", + "rv32mi-p-csr", + "rv32ui-p-sh", + "rv32ui-p-lh", + "rv32uc-p-rvc", + "rv32mi-p-sbreak", + "rv32ui-p-sll") + + // TODO: for now only generate tests for the first core in the first subsystem + params(RocketTilesKey).headOption.map { tileParams => + val coreParams = tileParams.core + val vm = coreParams.useVM + val env = if (vm) List("p", "v") else List("p") + coreParams.fpu foreach { case cfg => + if (xlen == 32) { + tests ++= env.map(rv32uf) + if (cfg.fLen >= 64) + tests ++= env.map(rv32ud) + } else { + tests += rv32udBenchmarks + tests ++= env.map(rv64uf) + if (cfg.fLen >= 64) + tests ++= env.map(rv64ud) + } + } + if (coreParams.useAtomics) { + if (tileParams.dcache.flatMap(_.scratch).isEmpty) + tests ++= env.map(if (xlen == 64) rv64ua else rv32ua) + else + tests ++= env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC) + } + if (coreParams.useCompressed) tests ++= env.map(if (xlen == 64) rv64uc else rv32uc) + val (rvi, rvu) = + if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u) + else ((if (vm) rv32i else rv32pi), rv32u) + + tests ++= rvi.map(_ ("p")) + tests ++= (if (vm) List("v") else List()).flatMap(env => rvu.map(_ (env))) + tests += benchmarks + + /* Filter the regression tests based on what the Rocket Chip configuration supports */ + val extensions = { + val fd = coreParams.fpu.map { + case cfg if cfg.fLen >= 64 => "fd" + case _ => "f" + } + val m = coreParams.mulDiv.map { case _ => "m" } + fd ++ m ++ Seq(if (coreParams.useRVE) Some("e") else Some("i"), + if (coreParams.useAtomics) Some("a") else None, + if (coreParams.useCompressed) Some("c") else None) + .flatten + .mkString("") + } + val re = s"""^rv$xlen[usm][$extensions].+""".r + regressionTests.retain { + case re() => true + case _ => false + } + tests += new RegressionTestSuite(regressionTests) + } + tests + } + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val ropts = view[RocketChipOptions](annotations) + val tests = ropts.topPackage.get match { + case "freechips.rocketchip.system" => GenerateSystemTestSuites(annotations) + case _ => GenerateDefaultTestSuites() + } + + RocketTestSuiteAnnotation(tests) +: annotations + } + +} diff --git a/src/main/scala/stage/phases/Checks.scala b/src/main/scala/stage/phases/Checks.scala new file mode 100644 index 00000000000..fbfd8bb757a --- /dev/null +++ b/src/main/scala/stage/phases/Checks.scala @@ -0,0 +1,47 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage.phases + +import firrtl.AnnotationSeq +import firrtl.annotations.Annotation +import firrtl.options.{OptionsException, Phase, PreservesAll, TargetDirAnnotation} +import freechips.rocketchip.stage._ + +import scala.collection.mutable + +/** Checks for the correct type and number of command line arguments */ +class Checks extends Phase with PreservesAll[Phase] { + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val targetDir, topModule, configNames, outputBaseName = mutable.ListBuffer[Annotation]() + + annotations.foreach { + case a: TargetDirAnnotation => a +=: targetDir + case a: TopModuleAnnotation => a +=: topModule + case a: ConfigsAnnotation => a +=: configNames + case a: OutputBaseNameAnnotation => a +=: outputBaseName + case _ => + } + + def required(annoList: mutable.ListBuffer[Annotation], option: String): Unit = { + if (annoList.size != 1) { + throw new OptionsException(s"Exactly one $option required") + } + } + + def optional(annoList: mutable.ListBuffer[Annotation], option: String): Unit = { + if (annoList.size > 1) { + throw new OptionsException(s"Too many $option options have been specified") + } + } + + required(targetDir, "target directory") + required(topModule, "top module") + required(configNames, "configs string (','-delimited)") + + optional(outputBaseName, "output base name") + + annotations + } + +} diff --git a/src/main/scala/stage/phases/GenerateArtefacts.scala b/src/main/scala/stage/phases/GenerateArtefacts.scala new file mode 100644 index 00000000000..b678906d2d3 --- /dev/null +++ b/src/main/scala/stage/phases/GenerateArtefacts.scala @@ -0,0 +1,27 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage.phases + +import chisel3.stage.phases.Elaborate +import firrtl.AnnotationSeq +import firrtl.options.{Phase, PreservesAll, StageOptions} +import firrtl.options.Viewer.view +import freechips.rocketchip.stage.RocketChipOptions +import freechips.rocketchip.util.{ElaborationArtefacts, HasRocketChipStageUtils} + +/** Writes [[ElaborationArtefacts]] into files */ +class GenerateArtefacts extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils { + + override val prerequisites = Seq(classOf[Checks], classOf[Elaborate]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val targetDir = view[StageOptions](annotations).targetDir + + ElaborationArtefacts.files.foreach { case (extension, contents) => + writeOutputFile(targetDir, s"${view[RocketChipOptions](annotations).longName.get}.${extension}", contents ()) + } + + annotations + } + +} diff --git a/src/main/scala/stage/phases/GenerateFirrtlAnnos.scala b/src/main/scala/stage/phases/GenerateFirrtlAnnos.scala new file mode 100644 index 00000000000..c6641ef8048 --- /dev/null +++ b/src/main/scala/stage/phases/GenerateFirrtlAnnos.scala @@ -0,0 +1,42 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage.phases + +import chisel3.stage.phases.{Convert, Elaborate, MaybeAspectPhase} +import firrtl.AnnotationSeq +import firrtl.annotations.{Annotation, DeletedAnnotation, JsonProtocol} +import firrtl.options.Viewer.view +import firrtl.options.{Phase, PreservesAll, StageOptions, TargetDirAnnotation, Unserializable} +import freechips.rocketchip.stage.RocketChipOptions +import freechips.rocketchip.util.HasRocketChipStageUtils + +/** Writes FIRRTL annotations into a file */ +class GenerateFirrtlAnnos extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils { + + override val prerequisites = Seq(classOf[Checks], classOf[Elaborate], classOf[Convert], classOf[MaybeAspectPhase]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val targetDir = view[StageOptions](annotations).targetDir + val fileName = s"${view[RocketChipOptions](annotations).longName.get}.anno.json" + + val annos = scala.collection.mutable.Buffer[Annotation]() + annotations.flatMap { + case a: Unserializable => + Some(a) + case a: TargetDirAnnotation => + /** Don't serialize, in case of downstream FIRRTL call */ + Some(a) + case a @ DeletedAnnotation(_, _: Unserializable) => + /** [[DeletedAnnotation]]s of unserializable annotations cannot be serialized */ + Some(a) + case a => + annos += a + Some(a) + } + + writeOutputFile(targetDir, fileName, JsonProtocol.serialize(annos)) + + annotations + } + +} diff --git a/src/main/scala/stage/phases/GenerateROMs.scala b/src/main/scala/stage/phases/GenerateROMs.scala new file mode 100644 index 00000000000..7203cb2caa1 --- /dev/null +++ b/src/main/scala/stage/phases/GenerateROMs.scala @@ -0,0 +1,31 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage.phases + +import chisel3.stage.ChiselCircuitAnnotation +import chisel3.stage.phases.{Convert, Elaborate} +import firrtl.AnnotationSeq +import firrtl.options.{Phase, PreservesAll, StageOptions} +import firrtl.options.Viewer.view +import freechips.rocketchip.stage.RocketChipOptions +import freechips.rocketchip.util.HasRocketChipStageUtils + +/** Dumps ROM information into a file */ +class GenerateROMs extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils { + + override val prerequisites = Seq(classOf[Checks], classOf[Elaborate]) + override val dependents = Seq(classOf[Convert]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val targetDir = view[StageOptions](annotations).targetDir + val fileName = s"${view[RocketChipOptions](annotations).longName.get}.rom.conf" + + annotations.flatMap { + case a: ChiselCircuitAnnotation => + writeOutputFile(targetDir, fileName, enumerateROMs(a.circuit)) + Some(a) + case a => Some(a) + } + } + +} diff --git a/src/main/scala/stage/phases/GenerateTestSuiteMakefrags.scala b/src/main/scala/stage/phases/GenerateTestSuiteMakefrags.scala new file mode 100644 index 00000000000..94f7866770d --- /dev/null +++ b/src/main/scala/stage/phases/GenerateTestSuiteMakefrags.scala @@ -0,0 +1,33 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage.phases + +import chisel3.stage.phases.Elaborate +import firrtl.AnnotationSeq +import firrtl.options.{Phase, PreservesAll, StageOptions} +import firrtl.options.Viewer.view +import freechips.rocketchip.stage.RocketChipOptions +import freechips.rocketchip.system.TestGeneration +import freechips.rocketchip.util.HasRocketChipStageUtils + +/** Generates a make script to run tests in [[RocketTestSuiteAnnotation]]. */ +class GenerateTestSuiteMakefrags extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils { + + override val prerequisites = Seq(classOf[Checks], classOf[Elaborate]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val targetDir = view[StageOptions](annotations).targetDir + val fileName = s"${view[RocketChipOptions](annotations).longName.get}.d" + + annotations.flatMap { + case a: RocketTestSuiteAnnotation => + val makefrag = a.tests.groupBy(_.kind) + .map { case (kind, s) => TestGeneration.gen(kind, s) } + .mkString("\n") + writeOutputFile(targetDir, fileName, makefrag) + Some(a) + case a => Some(a) + } + } + +} diff --git a/src/main/scala/stage/phases/PreElaboration.scala b/src/main/scala/stage/phases/PreElaboration.scala new file mode 100644 index 00000000000..3a9435dca15 --- /dev/null +++ b/src/main/scala/stage/phases/PreElaboration.scala @@ -0,0 +1,39 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage.phases + +import chisel3.RawModule +import chisel3.stage.ChiselGeneratorAnnotation +import firrtl.AnnotationSeq +import firrtl.options.Viewer.view +import firrtl.options.{Phase, PreservesAll} +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.stage.RocketChipOptions +import freechips.rocketchip.util.HasRocketChipStageUtils + +/** Constructs a generator function that returns a top module with given config parameters */ +class PreElaboration extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils { + + override val prerequisites = Seq(classOf[Checks]) + override val dependents = Seq(classOf[chisel3.stage.phases.Elaborate]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + + val rOpts = view[RocketChipOptions](annotations) + val topMod = rOpts.topModule.get + + val config = getConfig(rOpts.configNames.get) + + val gen = () => + topMod + .getConstructor(classOf[Parameters]) + .newInstance(config) match { + case a: RawModule => a + case a: LazyModule => LazyModule(a).module + } + + ChiselGeneratorAnnotation(gen) +: annotations + } + +} diff --git a/src/main/scala/stage/phases/TransformAnnotations.scala b/src/main/scala/stage/phases/TransformAnnotations.scala new file mode 100644 index 00000000000..a49bd55a10b --- /dev/null +++ b/src/main/scala/stage/phases/TransformAnnotations.scala @@ -0,0 +1,23 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.stage.phases + +import chisel3.stage.ChiselOutputFileAnnotation +import chisel3.stage.phases.Emitter +import firrtl.AnnotationSeq +import firrtl.options.Viewer.view +import firrtl.options.{Phase, PreservesAll} +import freechips.rocketchip.stage.RocketChipOptions +import freechips.rocketchip.util.HasRocketChipStageUtils + +/** Transforms RocketChipAnnotations into those used by other stages */ +class TransformAnnotations extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils { + + override val prerequisites = Seq(classOf[Checks]) + override val dependents = Seq(classOf[Emitter]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + /** Construct output file annotation for emission */ + new ChiselOutputFileAnnotation(view[RocketChipOptions](annotations).longName.get) +: annotations + } +} diff --git a/src/main/scala/system/Generator.scala b/src/main/scala/system/Generator.scala deleted file mode 100644 index f430d985f09..00000000000 --- a/src/main/scala/system/Generator.scala +++ /dev/null @@ -1,111 +0,0 @@ -// See LICENSE.SiFive for license details. - -package freechips.rocketchip.system - -import freechips.rocketchip.subsystem.RocketTilesKey -import freechips.rocketchip.tile.XLen -import freechips.rocketchip.util.GeneratorApp - -import scala.collection.mutable.LinkedHashSet - -/** A Generator for platforms containing Rocket Subsystemes */ -object Generator extends GeneratorApp { - - override def addTestSuites { - import DefaultTestSuites._ - val xlen = params(XLen) - - val regressionTests = LinkedHashSet( - "rv64ud-v-fcvt", - "rv64ud-p-fdiv", - "rv64ud-v-fadd", - "rv64uf-v-fadd", - "rv64um-v-mul", - "rv64mi-p-breakpoint", - "rv64uc-v-rvc", - "rv64ud-v-structural", - "rv64si-p-wfi", - "rv64um-v-divw", - "rv64ua-v-lrsc", - "rv64ui-v-fence_i", - "rv64ud-v-fcvt_w", - "rv64uf-v-fmin", - "rv64ui-v-sb", - "rv64ua-v-amomax_d", - "rv64ud-v-move", - "rv64ud-v-fclass", - "rv64ua-v-amoand_d", - "rv64ua-v-amoxor_d", - "rv64si-p-sbreak", - "rv64ud-v-fmadd", - "rv64uf-v-ldst", - "rv64um-v-mulh", - "rv64si-p-dirty", - "rv32mi-p-ma_addr", - "rv32mi-p-csr", - "rv32ui-p-sh", - "rv32ui-p-lh", - "rv32uc-p-rvc", - "rv32mi-p-sbreak", - "rv32ui-p-sll") - - // TODO: for now only generate tests for the first core in the first subsystem - params(RocketTilesKey).headOption.map { tileParams => - val coreParams = tileParams.core - val vm = coreParams.useVM - val env = if (vm) List("p","v") else List("p") - coreParams.fpu foreach { case cfg => - if (xlen == 32) { - TestGeneration.addSuites(env.map(rv32uf)) - if (cfg.fLen >= 64) - TestGeneration.addSuites(env.map(rv32ud)) - } else { - TestGeneration.addSuite(rv32udBenchmarks) - TestGeneration.addSuites(env.map(rv64uf)) - if (cfg.fLen >= 64) - TestGeneration.addSuites(env.map(rv64ud)) - } - } - if (coreParams.useAtomics) { - if (tileParams.dcache.flatMap(_.scratch).isEmpty) - TestGeneration.addSuites(env.map(if (xlen == 64) rv64ua else rv32ua)) - else - TestGeneration.addSuites(env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC)) - } - if (coreParams.useCompressed) TestGeneration.addSuites(env.map(if (xlen == 64) rv64uc else rv32uc)) - val (rvi, rvu) = - if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u) - else ((if (vm) rv32i else rv32pi), rv32u) - - TestGeneration.addSuites(rvi.map(_("p"))) - TestGeneration.addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env)))) - TestGeneration.addSuite(benchmarks) - - /* Filter the regression tests based on what the Rocket Chip configuration supports */ - val extensions = { - val fd = coreParams.fpu.map { - case cfg if cfg.fLen >= 64 => "fd" - case _ => "f" - } - val m = coreParams.mulDiv.map{ case _ => "m" } - fd ++ m ++ Seq( if (coreParams.useRVE) Some("e") else Some("i"), - if (coreParams.useAtomics) Some("a") else None, - if (coreParams.useCompressed) Some("c") else None ) - .flatten - .mkString("") - } - val re = s"""^rv$xlen[usm][$extensions].+""".r - regressionTests.retain{ - case re() => true - case _ => false - } - TestGeneration.addSuite(new RegressionTestSuite(regressionTests)) - } - } - - generateFirrtl - generateAnno - generateTestSuiteMakefrags - generateROMs - generateArtefacts -} diff --git a/src/main/scala/system/RocketChipStageGenerator.scala b/src/main/scala/system/RocketChipStageGenerator.scala new file mode 100644 index 00000000000..ddfb60edc54 --- /dev/null +++ b/src/main/scala/system/RocketChipStageGenerator.scala @@ -0,0 +1,35 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.system + +import chisel3.stage.{ChiselCli, ChiselStage} +import firrtl.options.PhaseManager.PhaseDependency +import firrtl.options.{Phase, PreservesAll, Shell, StageMain} +import firrtl.stage.FirrtlCli +import freechips.rocketchip.stage.RocketChipCli + +class RocketChipStage extends ChiselStage with PreservesAll[Phase] { + + override val shell = new Shell("rocket-chip") with RocketChipCli with ChiselCli with FirrtlCli + override val targets: Seq[PhaseDependency] = Seq( + classOf[freechips.rocketchip.stage.phases.Checks], + classOf[freechips.rocketchip.stage.phases.TransformAnnotations], + classOf[freechips.rocketchip.stage.phases.PreElaboration], + classOf[chisel3.stage.phases.Checks], + classOf[chisel3.stage.phases.Elaborate], + classOf[freechips.rocketchip.stage.phases.GenerateROMs], + classOf[chisel3.stage.phases.AddImplicitOutputFile], + classOf[chisel3.stage.phases.AddImplicitOutputAnnotationFile], + classOf[chisel3.stage.phases.MaybeAspectPhase], + classOf[chisel3.stage.phases.Emitter], + classOf[chisel3.stage.phases.Convert], + classOf[freechips.rocketchip.stage.phases.GenerateFirrtlAnnos], + classOf[freechips.rocketchip.stage.phases.AddDefaultTests], + classOf[freechips.rocketchip.stage.phases.GenerateTestSuiteMakefrags], + classOf[freechips.rocketchip.stage.phases.GenerateArtefacts], + ) + + // TODO: need a RunPhaseAnnotation to inject phases into ChiselStage +} + +object Generator extends StageMain(new RocketChipStage) diff --git a/src/main/scala/system/RocketTestSuite.scala b/src/main/scala/system/RocketTestSuite.scala index d4c809c9714..3129e83e11e 100644 --- a/src/main/scala/system/RocketTestSuite.scala +++ b/src/main/scala/system/RocketTestSuite.scala @@ -61,16 +61,15 @@ object TestGeneration { def addSuites(s: Seq[RocketTestSuite]) { s.foreach(addSuite) } - def generateMakefrag: String = { - def gen(kind: String, s: Seq[RocketTestSuite]) = { - if(s.length > 0) { - val envs = s.groupBy(_.envName) - val targets = s.map(t => s"$$(${t.makeTargetName})").mkString(" ") - s.map(_.toString).mkString("\n") + - envs.filterKeys(_ != "").map( { - case (env,envsuites) => { - val suites = envsuites.map(t => s"$$(${t.makeTargetName})").mkString(" ") - s""" + private[rocketchip] def gen(kind: String, s: Seq[RocketTestSuite]) = { + if(s.length > 0) { + val envs = s.groupBy(_.envName) + val targets = s.map(t => s"$$(${t.makeTargetName})").mkString(" ") + s.map(_.toString).mkString("\n") + + envs.filterKeys(_ != "").map( { + case (env,envsuites) => { + val suites = envsuites.map(t => s"$$(${t.makeTargetName})").mkString(" ") + s""" run-$kind-$env-tests: $$(addprefix $$(output_dir)/, $$(addsuffix .out, $suites)) \t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED):(.*)/i )' $$^ /dev/null | perl -pe 'BEGIN { $$$$failed = 0 } $$$$failed = 1 if(/FAILED/i); END { exit($$$$failed) }' run-$kind-$env-tests-debug: $$(addprefix $$(output_dir)/, $$(addsuffix .vpd, $suites)) @@ -89,9 +88,10 @@ run-$kind-tests-fst: $$(addprefix $$(output_dir)/, $$(addsuffix .fst, $targets)) run-$kind-tests-fast: $$(addprefix $$(output_dir)/, $$(addsuffix .run, $targets)) \t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED):(.*)/i )' $$^ /dev/null | perl -pe 'BEGIN { $$$$failed = 0 } $$$$failed = 1 if(/FAILED/i); END { exit($$$$failed) }' """ - } else { "\n" } - } + } else { "\n" } + } + def generateMakeFrag: String = { suites.values.toSeq.groupBy(_.kind).map { case (kind, s) => gen(kind, s) }.mkString("\n") } @@ -99,7 +99,7 @@ run-$kind-tests-fast: $$(addprefix $$(output_dir)/, $$(addsuffix .run, $targets) object DefaultTestSuites { val rv32uiNames = LinkedHashSet( - "simple", "add", "addi", "and", "andi", "auipc", "beq", "bge", "bgeu", "blt", "bltu", "bne", "fence_i", + "simple", "add", "addi", "and", "andi", "auipc", "beq", "bge", "bgeu", "blt", "bltu", "bne", "fence_i", "jal", "jalr", "lb", "lbu", "lh", "lhu", "lui", "lw", "or", "ori", "sb", "sh", "sw", "sll", "slli", "slt", "slti", "sra", "srai", "srl", "srli", "sub", "xor", "xori") val rv32ui = new AssemblyTestSuite("rv32ui", rv32uiNames)(_) diff --git a/src/main/scala/unittest/Generator.scala b/src/main/scala/unittest/Generator.scala index 1fd96632f4c..01ef16886e5 100644 --- a/src/main/scala/unittest/Generator.scala +++ b/src/main/scala/unittest/Generator.scala @@ -2,9 +2,7 @@ package freechips.rocketchip.unittest -object Generator extends freechips.rocketchip.util.GeneratorApp { - generateFirrtl - generateAnno - generateTestSuiteMakefrags // TODO: Needed only for legacy make targets - generateArtefacts -} +import firrtl.options.StageMain +import freechips.rocketchip.system.RocketChipStage + +object Generator extends StageMain(new RocketChipStage) diff --git a/src/main/scala/util/GeneratorUtils.scala b/src/main/scala/util/GeneratorUtils.scala index 4578906ffb1..8d00dd85066 100644 --- a/src/main/scala/util/GeneratorUtils.scala +++ b/src/main/scala/util/GeneratorUtils.scala @@ -2,36 +2,14 @@ package freechips.rocketchip.util -import Chisel._ -import chisel3.RawModule -import chisel3.internal.firrtl.Circuit -// TODO: better job of Makefrag generation for non-RocketChip testing platforms import java.io.{File, FileWriter} -import firrtl.annotations.JsonProtocol -import freechips.rocketchip.config._ -import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.system.{DefaultTestSuites, TestGeneration} +import Chisel.throwException +import chipsalliance.rocketchip.config.{Config, Parameters} +import chisel3.internal.firrtl.Circuit -/** Representation of the information this Generator needs to collect from external sources. */ -case class ParsedInputNames( - targetDir: String, - topModuleProject: String, - topModuleClass: String, - configProject: String, - configs: String, - outputBaseName: Option[String]) { - val configClasses: Seq[String] = configs.split('_') - def prepend(prefix: String, suffix: String) = - if (prefix == "" || prefix == "_root_") suffix else (prefix + "." + suffix) - val fullConfigClasses: Seq[String] = configClasses.map(x => prepend(configProject, x)) - val fullTopModuleClass: String = prepend(topModuleProject, topModuleClass) -} +trait HasRocketChipStageUtils { -/** Common utilities we supply to all Generators. In particular, supplies the - * canonical ways of building various JVM elaboration-time structures. - */ -trait HasGeneratorUtilities { def getConfig(fullConfigClassNames: Seq[String]): Config = { new Config(fullConfigClassNames.foldRight(Parameters.empty) { case (currentName, config) => val currentConfig = try { @@ -44,22 +22,6 @@ trait HasGeneratorUtilities { }) } - def getParameters(names: Seq[String]): Parameters = getParameters(getConfig(names)) - - def getParameters(config: Config): Parameters = config.toInstance - - def elaborate(fullTopModuleClassName: String, params: Parameters): Circuit = { - val top = () => - Class.forName(fullTopModuleClassName) - .getConstructor(classOf[Parameters]) - .newInstance(params) match { - case m: RawModule => m - case l: LazyModule => LazyModule(l).module - } - - Driver.elaborate(top) - } - def enumerateROMs(circuit: Circuit): String = { val res = new StringBuilder val configs = @@ -74,73 +36,6 @@ trait HasGeneratorUtilities { } res.toString } -} - -/** Standardized command line interface for Scala entry point */ -trait GeneratorApp extends App with HasGeneratorUtilities { - lazy val names: ParsedInputNames = { - require(args.size == 5 || args.size == 6, "Usage: sbt> " + - "run TargetDir TopModuleProjectName TopModuleName " + - "ConfigProjectName ConfigNameString [OutputFilesBaseName]") - val base = - ParsedInputNames( - targetDir = args(0), - topModuleProject = args(1), - topModuleClass = args(2), - configProject = args(3), - configs = args(4), - outputBaseName = None) - - if (args.size == 6) { - base.copy(outputBaseName = Some(args(5))) - } else { - base - } - } - - // Canonical ways of building various JVM elaboration-time structures - lazy val td: String = names.targetDir - lazy val config: Config = getConfig(names.fullConfigClasses) - lazy val params: Parameters = config.toInstance - lazy val circuit: Circuit = elaborate(names.fullTopModuleClass, params) - - // Exhaustive name used to interface with external build tool targets - lazy val longName: String = names.outputBaseName.getOrElse(names.configProject + "." + names.configs) - - /** Output FIRRTL, which an external compiler can turn into Verilog. */ - def generateFirrtl { - Driver.dumpFirrtl(circuit, Some(new File(td, s"$longName.fir"))) // FIRRTL - } - - def generateAnno { - val annotationFile = new File(td, s"$longName.anno.json") - val af = new FileWriter(annotationFile) - af.write(JsonProtocol.serialize(circuit.annotations.map(_.toFirrtl))) - af.close() - } - - /** Output software test Makefrags, which provide targets for integration testing. */ - def generateTestSuiteMakefrags { - addTestSuites - writeOutputFile(td, s"$longName.d", TestGeneration.generateMakefrag) // Subsystem-specific test suites - } - - def addTestSuites { - TestGeneration.addSuite(DefaultTestSuites.groundtest64("p")) - TestGeneration.addSuite(DefaultTestSuites.emptyBmarks) - TestGeneration.addSuite(DefaultTestSuites.singleRegression) - } - - def generateROMs { - writeOutputFile(td, s"$longName.rom.conf", enumerateROMs(circuit)) - } - - /** Output files created as a side-effect of elaboration */ - def generateArtefacts { - ElaborationArtefacts.files.foreach { case (extension, contents) => - writeOutputFile(td, s"$longName.$extension", contents ()) - } - } def writeOutputFile(targetDir: String, fname: String, contents: String): File = { val f = new File(targetDir, fname) @@ -149,6 +44,7 @@ trait GeneratorApp extends App with HasGeneratorUtilities { fw.close f } + } object ElaborationArtefacts { diff --git a/src/test/scala/generatorTests/StageGeneratorSpec.scala b/src/test/scala/generatorTests/StageGeneratorSpec.scala new file mode 100644 index 00000000000..e5487a19185 --- /dev/null +++ b/src/test/scala/generatorTests/StageGeneratorSpec.scala @@ -0,0 +1,44 @@ +// See LICENSE.SiFive for license details. + +package generatorTests + +import java.io.File + +import chisel3.aop.injecting.InjectingAspect +import chisel3._ +import firrtl.options.TargetDirAnnotation +import freechips.rocketchip.stage.{ConfigsAnnotation, TopModuleAnnotation} +import freechips.rocketchip.system.{RocketChipStage, TestHarness} +import org.scalatest.FlatSpec + +/** run via SBT with + * > testOnly generatorTests.StageGeneratorSpec + * + * Output can be viewed in the testbuild directory. The wire named "hello" should show up in the generated + * *.anno.json file. + */ +class StageGeneratorSpec extends FlatSpec { + + val dummyAspect = InjectingAspect( + {dut: TestHarness => Seq(dut.dut)}, + {dut: freechips.rocketchip.system.ExampleRocketSystemModuleImp[freechips.rocketchip.system.ExampleRocketSystem] => + val dummyWire = Wire(UInt(3.W)).suggestName("hello") + dummyWire := 5.U + dontTouch(dummyWire) + } + ) + + "Test" should "pass" in { + val dirName = System.getProperty("user.dir") + "/testbuild" + val dir = new File(dirName) + if (!dir.exists()) dir.mkdirs() + + new RocketChipStage().run(Seq( + new TargetDirAnnotation(dirName), + new TopModuleAnnotation(Class.forName("freechips.rocketchip.system.TestHarness")), + new ConfigsAnnotation(Seq("freechips.rocketchip.system.DefaultConfig")), + dummyAspect + )) + } + +} \ No newline at end of file diff --git a/vsim/Makefrag b/vsim/Makefrag index f28f192a210..278384769af 100644 --- a/vsim/Makefrag +++ b/vsim/Makefrag @@ -64,14 +64,14 @@ VCS_OPTS = -notice -line +lint=all,noVCDE,noONGS,noUI -error=PCWM-L -timescale=1 # Build the simulator #-------------------------------------------------------------------- -simv = $(sim_dir)/simv-$(PROJECT)-$(CONFIG) +simv = $(sim_dir)/simv-$(PROJECT)-$(CONFIG_STR) $(simv) : $(sim_vsrcs) $(sim_csrcs) cd $(sim_dir) && \ rm -rf csrc && \ $(VCS) $(VCS_OPTS) -o $(simv) \ -debug_pp \ -simv_debug = $(sim_dir)/simv-$(PROJECT)-$(CONFIG)-debug +simv_debug = $(sim_dir)/simv-$(PROJECT)-$(CONFIG_STR)-debug $(simv_debug) : $(sim_vsrcs) $(sim_csrcs) cd $(sim_dir) && \ rm -rf csrc && \ diff --git a/vsim/Makefrag-verilog b/vsim/Makefrag-verilog index 9b0afa159a2..13e35373d37 100644 --- a/vsim/Makefrag-verilog +++ b/vsim/Makefrag-verilog @@ -10,7 +10,7 @@ verilog = $(generated_dir)/$(long_name).v $(generated_dir)/%.fir $(generated_dir)/%.d: $(FIRRTL_JAR) $(chisel_srcs) $(bootrom_img) mkdir -p $(dir $@) - cd $(base_dir) && $(SBT) "runMain $(PROJECT).Generator $(generated_dir) $(PROJECT) $(MODEL) $(CFG_PROJECT) $(CONFIG)" + cd $(base_dir) && $(SBT) "runMain $(PROJECT).Generator -td $(generated_dir) -T $(PROJECT).$(MODEL) -C $(CONFIG)" $(generated_dir)/%.v $(generated_dir)/%.conf: $(generated_dir)/%.fir $(FIRRTL_JAR) mkdir -p $(dir $@)