[WIP] Move RocketTestSuite generation into RocketchipGenerator
This commit is contained in:
		| @@ -13,8 +13,6 @@ import rocket._ | |||||||
| import rocket.Util._ | import rocket.Util._ | ||||||
| import util.ConfigUtils._ | import util.ConfigUtils._ | ||||||
| import rocketchip.{GlobalAddrMap, NCoreplexExtClients} | import rocketchip.{GlobalAddrMap, NCoreplexExtClients} | ||||||
| import scala.collection.mutable.{LinkedHashSet, ListBuffer} |  | ||||||
| import DefaultTestSuites._ |  | ||||||
| import cde.{Parameters, Config, Dump, Knob, CDEMatchError} | import cde.{Parameters, Config, Dump, Knob, CDEMatchError} | ||||||
|  |  | ||||||
| class BaseCoreplexConfig extends Config ( | class BaseCoreplexConfig extends Config ( | ||||||
| @@ -71,28 +69,6 @@ class BaseCoreplexConfig extends Config ( | |||||||
|       case NUncachedTileLinkPorts => 1 |       case NUncachedTileLinkPorts => 1 | ||||||
|       //Tile Constants |       //Tile Constants | ||||||
|       case BuildTiles => { |       case BuildTiles => { | ||||||
|         val env = if(site(UseVM)) List("p","v") else List("p") |  | ||||||
|         site(FPUKey) foreach { case cfg => |  | ||||||
|           if (site(XLen) == 32) { |  | ||||||
|             TestGeneration.addSuites(env.map(rv32ufNoDiv)) |  | ||||||
|           } else { |  | ||||||
|             TestGeneration.addSuite(rv32udBenchmarks) |  | ||||||
|             TestGeneration.addSuites(env.map(rv64ufNoDiv)) |  | ||||||
|             TestGeneration.addSuites(env.map(rv64udNoDiv)) |  | ||||||
|             if (cfg.divSqrt) { |  | ||||||
|               TestGeneration.addSuites(env.map(rv64uf)) |  | ||||||
|               TestGeneration.addSuites(env.map(rv64ud)) |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         if (site(UseAtomics)) TestGeneration.addSuites(env.map(if (site(XLen) == 64) rv64ua else rv32ua)) |  | ||||||
|         if (site(UseCompressed)) TestGeneration.addSuites(env.map(if (site(XLen) == 64) rv64uc else rv32uc)) |  | ||||||
|         val (rvi, rvu) = |  | ||||||
|           if (site(XLen) == 64) ((if (site(UseVM)) rv64i else rv64pi), rv64u) |  | ||||||
|           else ((if (site(UseVM)) rv32i else rv32pi), rv32u) |  | ||||||
|         TestGeneration.addSuites(rvi.map(_("p"))) |  | ||||||
|         TestGeneration.addSuites((if(site(UseVM)) List("v") else List()).flatMap(env => rvu.map(_(env)))) |  | ||||||
|         TestGeneration.addSuite(benchmarks) |  | ||||||
|         List.tabulate(site(NTiles)){ i => (r: Bool, p: Parameters) => |         List.tabulate(site(NTiles)){ i => (r: Bool, p: Parameters) => | ||||||
|           Module(new RocketTile(resetSignal = r)(p.alterPartial({ |           Module(new RocketTile(resetSignal = r)(p.alterPartial({ | ||||||
|             case TileId => i |             case TileId => i | ||||||
| @@ -187,32 +163,6 @@ class BaseCoreplexConfig extends Config ( | |||||||
|       case CacheBlockBytes => Dump("CACHE_BLOCK_BYTES", 64) |       case CacheBlockBytes => Dump("CACHE_BLOCK_BYTES", 64) | ||||||
|       case CacheBlockOffsetBits => log2Up(here(CacheBlockBytes)) |       case CacheBlockOffsetBits => log2Up(here(CacheBlockBytes)) | ||||||
|       case EnableL2Logging => false |       case EnableL2Logging => false | ||||||
|       case RegressionTestNames => 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") |  | ||||||
|       case _ => throw new CDEMatchError |       case _ => throw new CDEMatchError | ||||||
|   }}, |   }}, | ||||||
|   knobValues = { |   knobValues = { | ||||||
| @@ -327,14 +277,6 @@ class WithRV32 extends Config( | |||||||
|   (pname,site,here) => pname match { |   (pname,site,here) => pname match { | ||||||
|     case XLen => 32 |     case XLen => 32 | ||||||
|     case FPUKey => Some(FPUConfig(divSqrt = false)) |     case FPUKey => Some(FPUConfig(divSqrt = false)) | ||||||
|     case RegressionTestNames => LinkedHashSet( |  | ||||||
|       "rv32mi-p-ma_addr", |  | ||||||
|       "rv32mi-p-csr", |  | ||||||
|       "rv32ui-p-sh", |  | ||||||
|       "rv32ui-p-lh", |  | ||||||
|       "rv32uc-p-rvc", |  | ||||||
|       "rv32mi-p-sbreak", |  | ||||||
|       "rv32ui-p-sll") |  | ||||||
|     case _ => throw new CDEMatchError |     case _ => throw new CDEMatchError | ||||||
|   } |   } | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -7,8 +7,6 @@ import uncore.coherence._ | |||||||
| import uncore.agents._ | import uncore.agents._ | ||||||
| import uncore.devices.NTiles | import uncore.devices.NTiles | ||||||
| import junctions._ | import junctions._ | ||||||
| import scala.collection.mutable.LinkedHashSet |  | ||||||
| import scala.collection.immutable.HashMap |  | ||||||
| import cde.{Parameters, Config, Dump, Knob, CDEMatchError} | import cde.{Parameters, Config, Dump, Knob, CDEMatchError} | ||||||
| import scala.math.max | import scala.math.max | ||||||
| import coreplex._ | import coreplex._ | ||||||
| @@ -125,7 +123,6 @@ class WithGroundTest extends Config( | |||||||
|     case FPUKey => None |     case FPUKey => None | ||||||
|     case UseAtomics => false |     case UseAtomics => false | ||||||
|     case UseCompressed => false |     case UseCompressed => false | ||||||
|     case RegressionTestNames => LinkedHashSet("rv64ui-p-simple") |  | ||||||
|     case _ => throw new CDEMatchError |     case _ => throw new CDEMatchError | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ import junctions._ | |||||||
| import uncore.tilelink._ | import uncore.tilelink._ | ||||||
| import uncore.tilelink2._ | import uncore.tilelink2._ | ||||||
| import uncore.devices._ | import uncore.devices._ | ||||||
| import util.ParameterizedBundle | import util.{ParameterizedBundle, ConfigStringOutput} | ||||||
| import rocket._ | import rocket._ | ||||||
| import rocket.Util._ | import rocket.Util._ | ||||||
| import coreplex._ | import coreplex._ | ||||||
|   | |||||||
| @@ -3,121 +3,79 @@ | |||||||
| package rocketchip | package rocketchip | ||||||
|  |  | ||||||
| import Chisel._ | import Chisel._ | ||||||
| import scala.collection.mutable.{LinkedHashSet,LinkedHashMap} | import rocket.{XLen, UseVM, UseAtomics, UseCompressed, FPUKey} | ||||||
| import cde._ | import util.Generator | ||||||
| import coreplex._ | import scala.collection.mutable.LinkedHashSet | ||||||
| import java.io.{File, FileWriter} |  | ||||||
|  |  | ||||||
| /** 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) { |  | ||||||
|   val configClasses: Seq[String] = configs.split('_') |  | ||||||
|   val fullConfigClasses: Seq[String] = configClasses.map(configProject + "." + _) |  | ||||||
|   val fullTopModuleClass: String = topModuleProject + "." + topModuleClass |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** Common utilities we supply to all Generators. In particular, supplies the |  | ||||||
|   * canonical ways of building various JVM elaboration-time structures. |  | ||||||
|   */ |  | ||||||
| trait HasGeneratorUtilities { |  | ||||||
|   def getConfig(names: ParsedInputNames): Config = { |  | ||||||
|     names.fullConfigClasses.foldRight(new Config()) { case (currentName, config) => |  | ||||||
|       val currentConfig = try { |  | ||||||
|         Class.forName(currentName).newInstance.asInstanceOf[Config] |  | ||||||
|       } catch { |  | ||||||
|         case e: java.lang.ClassNotFoundException => |  | ||||||
|           throwException(s"""Unable to find part "$currentName" from "${names.configs}", did you misspell it?""", e) |  | ||||||
|       } |  | ||||||
|       currentConfig ++ config |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   def getParameters(names: ParsedInputNames): Parameters = getParameters(getConfig(names)) |  | ||||||
|  |  | ||||||
|   def getParameters(config: Config): Parameters = Parameters.root(config.toInstance) |  | ||||||
|  |  | ||||||
|   import chisel3.internal.firrtl.Circuit |  | ||||||
|   def elaborate(names: ParsedInputNames, params: Parameters): Circuit = { |  | ||||||
|     val gen = () => |  | ||||||
|       Class.forName(names.fullTopModuleClass) |  | ||||||
|         .getConstructor(classOf[cde.Parameters]) |  | ||||||
|         .newInstance(params) |  | ||||||
|         .asInstanceOf[Module] |  | ||||||
|  |  | ||||||
|     Driver.elaborate(gen) |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   def writeOutputFile(targetDir: String, fname: String, contents: String): File = { |  | ||||||
|     val f = new File(targetDir, fname)  |  | ||||||
|     val fw = new FileWriter(f) |  | ||||||
|     fw.write(contents) |  | ||||||
|     fw.close |  | ||||||
|     f |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /** Standardized command line interface for Scala entry point */ |  | ||||||
| trait Generator extends App with HasGeneratorUtilities { |  | ||||||
|   lazy val names: ParsedInputNames = { |  | ||||||
|     require(args.size == 5, "Usage: sbt> " +  |  | ||||||
|       "run TargetDir TopModuleProjectName TopModuleName ConfigProjectName ConfigNameString") |  | ||||||
|     ParsedInputNames( |  | ||||||
|       targetDir = args(0), |  | ||||||
|       topModuleProject = args(1), |  | ||||||
|       topModuleClass = args(2), |  | ||||||
|       configProject = args(3), |  | ||||||
|       configs = args(4)) |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Canonical ways of building various JVM elaboration-time structures |  | ||||||
|   lazy val td = names.targetDir |  | ||||||
|   lazy val config = getConfig(names) |  | ||||||
|   lazy val world = config.toInstance |  | ||||||
|   lazy val params = Parameters.root(world) |  | ||||||
|   lazy val circuit = elaborate(names, params) |  | ||||||
|  |  | ||||||
|   val longName: String // Exhaustive name used to interface with external build tool targets |  | ||||||
|  |  | ||||||
|   /** Output FIRRTL, which an external compiler can turn into Verilog. */ |  | ||||||
|   def generateFirrtl { |  | ||||||
|     Driver.dumpFirrtl(circuit, Some(new File(td, s"$longName.fir"))) // FIRRTL |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** Output software test Makefrags, which provide targets for integration testing. */ |  | ||||||
|   def generateTestSuiteMakefrags { |  | ||||||
|     TestGeneration.addSuite(new RegressionTestSuite(params(RegressionTestNames))) |  | ||||||
|     writeOutputFile(td, s"$longName.d", TestGeneration.generateMakefrag) // Coreplex-specific test suites |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** Output Design Space Exploration knobs and constraints. */ |  | ||||||
|   def generateDSEConstraints { |  | ||||||
|     writeOutputFile(td, s"${names.configs}.knb", world.getKnobs) // Knobs for DSE |  | ||||||
|     writeOutputFile(td, s"${names.configs}.cst", world.getConstraints) // Constraints for DSE |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** Output a global Parameter dump, which an external script can turn into Verilog headers. */ |  | ||||||
|   def generateParameterDump { |  | ||||||
|     writeOutputFile(td, s"$longName.prm", ParameterDump.getDump) // Parameters flagged with Dump() |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** Output a global ConfigString, for use by the RISC-V software ecosystem. */ |  | ||||||
|   def generateConfigString { |  | ||||||
|     ConfigStringOutput.contents.foreach(c => writeOutputFile(td, s"${names.configs}.cfg", c)) // String for software |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| object ConfigStringOutput { |  | ||||||
|   var contents: Option[String] = None |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** An example Generator */ | /** An example Generator */ | ||||||
| object RocketChipGenerator extends Generator | object RocketChipGenerator extends Generator | ||||||
| { | { | ||||||
|  |   val rv64RegrTestNames = LinkedHashSet( | ||||||
|  |         "rv64ud-v-fcvt", | ||||||
|  |         "rv64ud-p-fdiv", | ||||||
|  |         "rv64ud-v-fadd", | ||||||
|  |         "rv64uf-v-fadd", | ||||||
|  |         "rv64um-v-mul", | ||||||
|  |         "rv64mi-p-breakpoint", | ||||||
|  |         "rv64uc-v-rvc", | ||||||
|  |         "rv64ud-v-structural", | ||||||
|  |         "rv64si-p-wfi", | ||||||
|  |         "rv64um-v-divw", | ||||||
|  |         "rv64ua-v-lrsc", | ||||||
|  |         "rv64ui-v-fence_i", | ||||||
|  |         "rv64ud-v-fcvt_w", | ||||||
|  |         "rv64uf-v-fmin", | ||||||
|  |         "rv64ui-v-sb", | ||||||
|  |         "rv64ua-v-amomax_d", | ||||||
|  |         "rv64ud-v-move", | ||||||
|  |         "rv64ud-v-fclass", | ||||||
|  |         "rv64ua-v-amoand_d", | ||||||
|  |         "rv64ua-v-amoxor_d", | ||||||
|  |         "rv64si-p-sbreak", | ||||||
|  |         "rv64ud-v-fmadd", | ||||||
|  |         "rv64uf-v-ldst", | ||||||
|  |         "rv64um-v-mulh", | ||||||
|  |         "rv64si-p-dirty") | ||||||
|  |  | ||||||
|  |   val rv32RegrTestNames = LinkedHashSet( | ||||||
|  |       "rv32mi-p-ma_addr", | ||||||
|  |       "rv32mi-p-csr", | ||||||
|  |       "rv32ui-p-sh", | ||||||
|  |       "rv32ui-p-lh", | ||||||
|  |       "rv32uc-p-rvc", | ||||||
|  |       "rv32mi-p-sbreak", | ||||||
|  |       "rv32ui-p-sll") | ||||||
|  |  | ||||||
|  |   override def addTestSuites { | ||||||
|  |     import DefaultTestSuites._ | ||||||
|  |     val xlen = params(XLen) | ||||||
|  |     val vm = params(UseVM) | ||||||
|  |     val env = if (vm) List("p","v") else List("p") | ||||||
|  |     params(FPUKey) foreach { case cfg => | ||||||
|  |       if (xlen == 32) { | ||||||
|  |         TestGeneration.addSuites(env.map(rv32ufNoDiv)) | ||||||
|  |       } else { | ||||||
|  |         TestGeneration.addSuite(rv32udBenchmarks) | ||||||
|  |         TestGeneration.addSuites(env.map(rv64ufNoDiv)) | ||||||
|  |         TestGeneration.addSuites(env.map(rv64udNoDiv)) | ||||||
|  |         if (cfg.divSqrt) { | ||||||
|  |           TestGeneration.addSuites(env.map(rv64uf)) | ||||||
|  |           TestGeneration.addSuites(env.map(rv64ud)) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if (params(UseAtomics))    TestGeneration.addSuites(env.map(if (xlen == 64) rv64ua else rv32ua)) | ||||||
|  |     if (params(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) | ||||||
|  |     TestGeneration.addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames)) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   val longName = names.topModuleProject + "." + names.configs |   val longName = names.topModuleProject + "." + names.configs | ||||||
|   generateFirrtl |   generateFirrtl | ||||||
|   generateTestSuiteMakefrags |   generateTestSuiteMakefrags | ||||||
|   | |||||||
| @@ -1,12 +1,9 @@ | |||||||
| // See LICENSE for license details. | // See LICENSE for license details. | ||||||
| 
 | 
 | ||||||
| package coreplex | package rocketchip | ||||||
| 
 | 
 | ||||||
| import Chisel._ | import Chisel._ | ||||||
| import scala.collection.mutable.{LinkedHashSet,LinkedHashMap} | import scala.collection.mutable.{LinkedHashSet, LinkedHashMap} | ||||||
| import cde.{Parameters, ParameterDump, Config, Field, CDEMatchError} |  | ||||||
| 
 |  | ||||||
| case object RegressionTestNames extends Field[LinkedHashSet[String]] |  | ||||||
| 
 | 
 | ||||||
| abstract class RocketTestSuite { | abstract class RocketTestSuite { | ||||||
|   val dir: String |   val dir: String | ||||||
| @@ -175,6 +172,8 @@ object DefaultTestSuites { | |||||||
|   val emptyBmarks = new BenchmarkTestSuite("empty", |   val emptyBmarks = new BenchmarkTestSuite("empty", | ||||||
|     "$(RISCV)/riscv64-unknown-elf/share/riscv-tests/benchmarks", LinkedHashSet.empty) |     "$(RISCV)/riscv64-unknown-elf/share/riscv-tests/benchmarks", LinkedHashSet.empty) | ||||||
| 
 | 
 | ||||||
|  |   val singleRegression = new RegressionTestSuite(LinkedHashSet("rv64iu-p-simple")) | ||||||
|  | 
 | ||||||
|   val mtBmarks = new BenchmarkTestSuite("mt", "$(RISCV)/riscv64-unknown-elf/share/riscv-tests/mt", |   val mtBmarks = new BenchmarkTestSuite("mt", "$(RISCV)/riscv64-unknown-elf/share/riscv-tests/mt", | ||||||
|     LinkedHashSet(((0 to 4).map("vvadd"+_) ++ |     LinkedHashSet(((0 to 4).map("vvadd"+_) ++ | ||||||
|     List("ad","ae","af","ag","ai","ak","al","am","an","ap","aq","ar","at","av","ay","az", |     List("ad","ae","af","ag","ai","ak","al","am","an","ap","aq","ar","at","av","ay","az", | ||||||
| @@ -4,37 +4,32 @@ package unittest | |||||||
|  |  | ||||||
| import Chisel._ | import Chisel._ | ||||||
| import cde.{Parameters, Config, CDEMatchError} | import cde.{Parameters, Config, CDEMatchError} | ||||||
| import coreplex.{TestGeneration, DefaultTestSuites} | import rocketchip.{BaseConfig, BasePlatformConfig} | ||||||
| import rocketchip.BaseConfig |  | ||||||
|  |  | ||||||
| class WithJunctionsUnitTests extends Config( | class WithJunctionsUnitTests extends Config( | ||||||
|   (pname, site, here) => pname match { |   (pname, site, here) => pname match { | ||||||
|     case UnitTests => (p: Parameters) => { |     case junctions.PAddrBits => 32 | ||||||
|       TestGeneration.addSuite(DefaultTestSuites.groundtest64("p")) // TODO why |     case rocket.XLen => 64 | ||||||
|       TestGeneration.addSuite(DefaultTestSuites.emptyBmarks) |     case UnitTests => (p: Parameters) => Seq( | ||||||
|       Seq( |       Module(new junctions.MultiWidthFifoTest), | ||||||
|         Module(new junctions.MultiWidthFifoTest), |       Module(new junctions.NastiMemoryDemuxTest()(p)), | ||||||
|         Module(new junctions.NastiMemoryDemuxTest()(p)), |       Module(new junctions.HastiTest()(p))) | ||||||
|         Module(new junctions.HastiTest()(p))) |  | ||||||
|     } |  | ||||||
|     case _ => throw new CDEMatchError |     case _ => throw new CDEMatchError | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|  | class JunctionsUnitTestConfig extends Config(new WithJunctionsUnitTests ++ new BasePlatformConfig) | ||||||
|  |  | ||||||
| class WithUncoreUnitTests extends Config( | class WithUncoreUnitTests extends Config( | ||||||
|   (pname, site, here) => pname match { |   (pname, site, here) => pname match { | ||||||
|     case rocketchip.NCoreplexExtClients => 0 |     case rocketchip.NCoreplexExtClients => 0 | ||||||
|     case uncore.tilelink.TLId => "L1toL2" |     case uncore.tilelink.TLId => "L1toL2" | ||||||
|     case UnitTests => (p: Parameters) => { |     case UnitTests => (p: Parameters) => Seq( | ||||||
|       TestGeneration.addSuite(DefaultTestSuites.groundtest64("p")) // TODO why |       Module(new uncore.devices.ROMSlaveTest()(p)), | ||||||
|       TestGeneration.addSuite(DefaultTestSuites.emptyBmarks) |       Module(new uncore.devices.TileLinkRAMTest()(p)), | ||||||
|       Seq( |       Module(new uncore.tilelink2.TLFuzzRAMTest)) | ||||||
|         Module(new uncore.devices.ROMSlaveTest()(p)), |  | ||||||
|         Module(new uncore.devices.TileLinkRAMTest()(p)), |  | ||||||
|         Module(new uncore.tilelink2.TLFuzzRAMTest) |  | ||||||
|       ) |  | ||||||
|     } |  | ||||||
|     case _ => throw new CDEMatchError |     case _ => throw new CDEMatchError | ||||||
|   } |   } | ||||||
| ) | ) | ||||||
|  |  | ||||||
| class UnitTestConfig extends Config(new WithUncoreUnitTests ++ new WithJunctionsUnitTests ++ new BaseConfig) | class UncoreUnitTestConfig extends Config(new WithUncoreUnitTests ++ new BaseConfig) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										125
									
								
								src/main/scala/util/GeneratorUtils.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								src/main/scala/util/GeneratorUtils.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | // See LICENSE for license details. | ||||||
|  |  | ||||||
|  | package util | ||||||
|  |  | ||||||
|  | import Chisel._ | ||||||
|  | import cde._ | ||||||
|  | import java.io.{File, FileWriter} | ||||||
|  |  | ||||||
|  | /** 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) { | ||||||
|  |   val configClasses: Seq[String] = configs.split('_') | ||||||
|  |   val fullConfigClasses: Seq[String] = configClasses.map(configProject + "." + _) | ||||||
|  |   val fullTopModuleClass: String = topModuleProject + "." + topModuleClass | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Common utilities we supply to all Generators. In particular, supplies the | ||||||
|  |   * canonical ways of building various JVM elaboration-time structures. | ||||||
|  |   */ | ||||||
|  | trait HasGeneratorUtilities { | ||||||
|  |   def getConfig(names: ParsedInputNames): Config = { | ||||||
|  |     names.fullConfigClasses.foldRight(new Config()) { case (currentName, config) => | ||||||
|  |       val currentConfig = try { | ||||||
|  |         Class.forName(currentName).newInstance.asInstanceOf[Config] | ||||||
|  |       } catch { | ||||||
|  |         case e: java.lang.ClassNotFoundException => | ||||||
|  |           throwException(s"""Unable to find part "$currentName" from "${names.configs}", did you misspell it?""", e) | ||||||
|  |       } | ||||||
|  |       currentConfig ++ config | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   def getParameters(names: ParsedInputNames): Parameters = getParameters(getConfig(names)) | ||||||
|  |  | ||||||
|  |   def getParameters(config: Config): Parameters = Parameters.root(config.toInstance) | ||||||
|  |  | ||||||
|  |   import chisel3.internal.firrtl.Circuit | ||||||
|  |   def elaborate(names: ParsedInputNames, params: Parameters): Circuit = { | ||||||
|  |     val gen = () => | ||||||
|  |       Class.forName(names.fullTopModuleClass) | ||||||
|  |         .getConstructor(classOf[cde.Parameters]) | ||||||
|  |         .newInstance(params) | ||||||
|  |         .asInstanceOf[Module] | ||||||
|  |  | ||||||
|  |     Driver.elaborate(gen) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   def writeOutputFile(targetDir: String, fname: String, contents: String): File = { | ||||||
|  |     val f = new File(targetDir, fname)  | ||||||
|  |     val fw = new FileWriter(f) | ||||||
|  |     fw.write(contents) | ||||||
|  |     fw.close | ||||||
|  |     f | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** Standardized command line interface for Scala entry point */ | ||||||
|  | trait Generator extends App with HasGeneratorUtilities { | ||||||
|  |   lazy val names: ParsedInputNames = { | ||||||
|  |     require(args.size == 5, "Usage: sbt> " +  | ||||||
|  |       "run TargetDir TopModuleProjectName TopModuleName " + | ||||||
|  |       "ConfigProjectName ConfigNameString") | ||||||
|  |     ParsedInputNames( | ||||||
|  |       targetDir = args(0), | ||||||
|  |       topModuleProject = args(1), | ||||||
|  |       topModuleClass = args(2), | ||||||
|  |       configProject = args(3), | ||||||
|  |       configs = args(4)) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Canonical ways of building various JVM elaboration-time structures | ||||||
|  |   lazy val td = names.targetDir | ||||||
|  |   lazy val config = getConfig(names) | ||||||
|  |   lazy val world = config.toInstance | ||||||
|  |   lazy val params = Parameters.root(world) | ||||||
|  |   lazy val circuit = elaborate(names, params) | ||||||
|  |  | ||||||
|  |   val longName: String // Exhaustive name used to interface with external build tool targets | ||||||
|  |  | ||||||
|  |   /** Output FIRRTL, which an external compiler can turn into Verilog. */ | ||||||
|  |   def generateFirrtl { | ||||||
|  |     Driver.dumpFirrtl(circuit, Some(new File(td, s"$longName.fir"))) // FIRRTL | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** Output software test Makefrags, which provide targets for integration testing. */ | ||||||
|  |   def generateTestSuiteMakefrags { | ||||||
|  |     addTestSuites | ||||||
|  |     writeOutputFile(td, s"$longName.d", rocketchip.TestGeneration.generateMakefrag) // Coreplex-specific test suites | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   def addTestSuites { | ||||||
|  |     // TODO: better job of Makefrag generation | ||||||
|  |     //       for non-RocketChip testing platforms | ||||||
|  |     import rocketchip.{DefaultTestSuites, TestGeneration} | ||||||
|  |     TestGeneration.addSuite(DefaultTestSuites.groundtest64("p")) | ||||||
|  |     TestGeneration.addSuite(DefaultTestSuites.emptyBmarks) | ||||||
|  |     TestGeneration.addSuite(DefaultTestSuites.singleRegression) | ||||||
|  |   }  | ||||||
|  |  | ||||||
|  |   /** Output Design Space Exploration knobs and constraints. */ | ||||||
|  |   def generateDSEConstraints { | ||||||
|  |     writeOutputFile(td, s"${names.configs}.knb", world.getKnobs) // Knobs for DSE | ||||||
|  |     writeOutputFile(td, s"${names.configs}.cst", world.getConstraints) // Constraints for DSE | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** Output a global Parameter dump, which an external script can turn into Verilog headers. */ | ||||||
|  |   def generateParameterDump { | ||||||
|  |     writeOutputFile(td, s"$longName.prm", ParameterDump.getDump) // Parameters flagged with Dump() | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** Output a global ConfigString, for use by the RISC-V software ecosystem. */ | ||||||
|  |   def generateConfigString { | ||||||
|  |     ConfigStringOutput.contents.foreach(c => writeOutputFile(td, s"${names.configs}.cfg", c)) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | object ConfigStringOutput { | ||||||
|  |   var contents: Option[String] = None | ||||||
|  | } | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user