summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJack2021-12-18 08:27:38 +0000
committerJack2021-12-18 08:27:38 +0000
commitdd9ad534771247ac16eaa47eb9794102736b5102 (patch)
treed4566d317cb8526b79017de1e438aea8217dd1d4 /src
parent440edc4436fb3a8a4175ae425a0d31c4997ee60f (diff)
parentf50f74f583fba7b98e550c440df091e559ce32b8 (diff)
Merge branch 'master' into 3.5-release
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/chisel3/ChiselExecutionOptions.scala49
-rw-r--r--src/main/scala/chisel3/Driver.scala145
-rw-r--r--src/main/scala/chisel3/aop/Select.scala180
-rw-r--r--src/main/scala/chisel3/aop/injecting/InjectingAspect.scala2
-rw-r--r--src/main/scala/chisel3/compatibility.scala9
-rw-r--r--src/main/scala/chisel3/experimental/conversions/package.scala128
-rw-r--r--src/main/scala/chisel3/experimental/verification/package.scala27
-rw-r--r--src/main/scala/chisel3/stage/package.scala29
-rw-r--r--src/main/scala/chisel3/stage/phases/DriverCompatibility.scala16
-rw-r--r--src/main/scala/chisel3/testers/BasicTester.scala7
-rw-r--r--src/main/scala/chisel3/util/Arbiter.scala17
-rw-r--r--src/main/scala/chisel3/util/BitPat.scala218
-rw-r--r--src/main/scala/chisel3/util/Decoupled.scala110
-rw-r--r--src/main/scala/chisel3/util/Enum.scala1
-rw-r--r--src/main/scala/chisel3/util/Valid.scala23
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala15
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala19
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/TruthTable.scala47
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/decoder.scala35
-rw-r--r--src/main/scala/chisel3/util/random/GaloisLFSR.scala4
-rw-r--r--src/main/scala/chisel3/util/random/PRNG.scala15
-rw-r--r--src/test/scala/chisel3/testers/TestUtils.scala9
-rw-r--r--src/test/scala/chiselTests/AutoClonetypeSpec.scala199
-rw-r--r--src/test/scala/chiselTests/AutoNestedCloneSpec.scala65
-rw-r--r--src/test/scala/chiselTests/BlackBoxImpl.scala1
-rw-r--r--src/test/scala/chiselTests/BundleSpec.scala33
-rw-r--r--src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala5
-rw-r--r--src/test/scala/chiselTests/CompatibilitySpec.scala33
-rw-r--r--src/test/scala/chiselTests/CompileOptionsTest.scala2
-rw-r--r--src/test/scala/chiselTests/ComplexAssign.scala5
-rw-r--r--src/test/scala/chiselTests/ConnectSpec.scala35
-rw-r--r--src/test/scala/chiselTests/DataPrint.scala56
-rw-r--r--src/test/scala/chiselTests/FixedPointSpec.scala3
-rw-r--r--src/test/scala/chiselTests/Harness.scala5
-rw-r--r--src/test/scala/chiselTests/InlineSpec.scala1
-rw-r--r--src/test/scala/chiselTests/IntervalSpec.scala9
-rw-r--r--src/test/scala/chiselTests/InvalidateAPISpec.scala2
-rw-r--r--src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala1
-rw-r--r--src/test/scala/chiselTests/Module.scala66
-rw-r--r--src/test/scala/chiselTests/PrintableSpec.scala9
-rw-r--r--src/test/scala/chiselTests/QueueFlushSpec.scala20
-rw-r--r--src/test/scala/chiselTests/QueueSpec.scala30
-rw-r--r--src/test/scala/chiselTests/RecordSpec.scala25
-rw-r--r--src/test/scala/chiselTests/SIntOps.scala2
-rw-r--r--src/test/scala/chiselTests/StrongEnum.scala4
-rw-r--r--src/test/scala/chiselTests/TransitNameSpec.scala1
-rw-r--r--src/test/scala/chiselTests/UIntOps.scala84
-rw-r--r--src/test/scala/chiselTests/Vec.scala34
-rw-r--r--src/test/scala/chiselTests/VecLiteralSpec.scala48
-rw-r--r--src/test/scala/chiselTests/VerificationSpec.scala (renamed from src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala)35
-rw-r--r--src/test/scala/chiselTests/aop/SelectSpec.scala7
-rw-r--r--src/test/scala/chiselTests/experimental/DataView.scala123
-rw-r--r--src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala3
-rw-r--r--src/test/scala/chiselTests/experimental/TraceSpec.scala309
-rw-r--r--src/test/scala/chiselTests/experimental/Tuple.scala163
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala12
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala55
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/Examples.scala53
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala156
-rw-r--r--src/test/scala/chiselTests/util/BitPatSpec.scala10
-rw-r--r--src/test/scala/chiselTests/util/BitSetSpec.scala119
-rw-r--r--src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala31
62 files changed, 2278 insertions, 681 deletions
diff --git a/src/main/scala/chisel3/ChiselExecutionOptions.scala b/src/main/scala/chisel3/ChiselExecutionOptions.scala
deleted file mode 100644
index 9f635b19..00000000
--- a/src/main/scala/chisel3/ChiselExecutionOptions.scala
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-package chisel3
-
-import chisel3.stage.{NoRunFirrtlCompilerAnnotation, PrintFullStackTraceAnnotation}
-
-import firrtl.{AnnotationSeq, ExecutionOptionsManager, ComposableOptions}
-
-//TODO: provide support for running firrtl as separate process, could alternatively be controlled by external driver
-//TODO: provide option for not saving chirrtl file, instead calling firrtl with in memory chirrtl
-/**
- * Options that are specific to chisel.
- *
- * @param runFirrtlCompiler when true just run chisel, when false run chisel then compile its output with firrtl
- * @note this extends FirrtlExecutionOptions which extends CommonOptions providing easy access to down chain options
- */
-case class ChiselExecutionOptions(
- runFirrtlCompiler: Boolean = true,
- printFullStackTrace: Boolean = false
- // var runFirrtlAsProcess: Boolean = false
- ) extends ComposableOptions {
-
- def toAnnotations: AnnotationSeq =
- (if (!runFirrtlCompiler) { Seq(NoRunFirrtlCompilerAnnotation) } else { Seq() }) ++
- (if (printFullStackTrace) { Some(PrintFullStackTraceAnnotation) } else { None })
-
-}
-
-trait HasChiselExecutionOptions {
- self: ExecutionOptionsManager =>
-
- var chiselOptions = ChiselExecutionOptions()
-
- parser.note("chisel3 options")
-
- parser.opt[Unit]("no-run-firrtl")
- .abbr("chnrf")
- .foreach { _ =>
- chiselOptions = chiselOptions.copy(runFirrtlCompiler = false)
- }
- .text("Stop after chisel emits chirrtl file")
-
- parser.opt[Unit]("full-stacktrace")
- .foreach { _ =>
- chiselOptions = chiselOptions.copy(printFullStackTrace = true)
- }
- .text("Do not trim stack trace")
-}
-
diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala
index fb564446..aa379629 100644
--- a/src/main/scala/chisel3/Driver.scala
+++ b/src/main/scala/chisel3/Driver.scala
@@ -2,85 +2,106 @@
package chisel3
-import chisel3.internal.ErrorLog
import internal.firrtl._
import firrtl._
-import firrtl.options.{Dependency, Phase, PhaseManager, StageError}
-import firrtl.options.phases.DeletedWrapper
-import firrtl.options.Viewer.view
-import firrtl.annotations.JsonProtocol
import firrtl.util.{BackendCompilationUtilities => FirrtlBackendCompilationUtilities}
-import chisel3.stage.{ChiselExecutionResultView, ChiselGeneratorAnnotation, ChiselStage}
-import chisel3.stage.phases.DriverCompatibility
import java.io._
+import _root_.logger.LazyLogging
+@deprecated("Use object firrtl.util.BackendCompilationUtilities instead", "Chisel 3.5")
+trait BackendCompilationUtilities extends LazyLogging {
-/**
- * The Driver provides methods to invoke the chisel3 compiler and the firrtl compiler.
- * By default firrtl is automatically run after chisel. an [[ExecutionOptionsManager]]
- * is needed to manage options. It can parser command line arguments or coordinate
- * multiple chisel toolchain tools options.
- *
- * @example
- * {{{
- * val optionsManager = new ExecutionOptionsManager("chisel3")
- * with HasFirrtlOptions
- * with HasChiselExecutionOptions {
- * commonOptions = CommonOption(targetDirName = "my_target_dir")
- * chiselOptions = ChiselExecutionOptions(runFirrtlCompiler = false)
- * }
- * chisel3.Driver.execute(optionsManager, () => new Dut)
- * }}}
- * or via command line arguments
- * @example {{{
- * args = "--no-run-firrtl --target-dir my-target-dir".split(" +")
- * chisel3.execute(args, () => new DUT)
- * }}}
- */
+ import scala.sys.process.{ProcessBuilder, ProcessLogger, _}
+
+ // Inlined from old trait firrtl.util.BackendCompilationUtilities
+ lazy val TestDirectory = FirrtlBackendCompilationUtilities.TestDirectory
+ def timeStamp: String = FirrtlBackendCompilationUtilities.timeStamp
+ def loggingProcessLogger: ProcessLogger = FirrtlBackendCompilationUtilities.loggingProcessLogger
+ def copyResourceToFile(name: String, file: File): Unit = FirrtlBackendCompilationUtilities.copyResourceToFile(name, file)
+ def createTestDirectory(testName: String): File = FirrtlBackendCompilationUtilities.createTestDirectory(testName)
+ def makeHarness(template: String => String, post: String)(f: File): File =
+ FirrtlBackendCompilationUtilities.makeHarness(template, post)(f)
+ def firrtlToVerilog(prefix: String, dir: File): ProcessBuilder =
+ FirrtlBackendCompilationUtilities.firrtlToVerilog(prefix, dir)
+ def verilogToCpp(
+ dutFile: String,
+ dir: File,
+ vSources: Seq[File],
+ cppHarness: File,
+ suppressVcd: Boolean = false,
+ resourceFileName: String = firrtl.transforms.BlackBoxSourceHelper.defaultFileListName
+ ): ProcessBuilder = {
+ FirrtlBackendCompilationUtilities.verilogToCpp(dutFile, dir, vSources, cppHarness, suppressVcd, resourceFileName)
+ }
+ def cppToExe(prefix: String, dir: File): ProcessBuilder = FirrtlBackendCompilationUtilities.cppToExe(prefix, dir)
+ def executeExpectingFailure(
+ prefix: String,
+ dir: File,
+ assertionMsg: String = ""
+ ): Boolean = {
+ FirrtlBackendCompilationUtilities.executeExpectingFailure(prefix, dir, assertionMsg)
+ }
+ def executeExpectingSuccess(prefix: String, dir: File): Boolean =
+ FirrtlBackendCompilationUtilities.executeExpectingSuccess(prefix, dir)
-trait BackendCompilationUtilities extends FirrtlBackendCompilationUtilities {
/** Compile Chirrtl to Verilog by invoking Firrtl inside the same JVM
*
* @param prefix basename of the file
* @param dir directory where file lives
* @return true if compiler completed successfully
*/
+ @deprecated("Use ChiselStage instead", "Chisel 3.5")
def compileFirrtlToVerilog(prefix: String, dir: File): Boolean = {
- val optionsManager = new ExecutionOptionsManager("chisel3") with HasChiselExecutionOptions with HasFirrtlOptions {
- commonOptions = CommonOptions(topName = prefix, targetDirName = dir.getAbsolutePath)
- firrtlOptions = FirrtlExecutionOptions(compilerName = "verilog")
+
+ // ====== Implemented by inlining logic from ExecutionsOptionManager.toAnnotations =====
+ import firrtl.stage.InfoModeAnnotation
+ import firrtl.stage.phases.DriverCompatibility.TopNameAnnotation
+ import _root_.logger.LogLevelAnnotation
+ val annos: AnnotationSeq = List(
+ InfoModeAnnotation("append"),
+ TopNameAnnotation(prefix),
+ TargetDirAnnotation(dir.getAbsolutePath),
+ LogLevelAnnotation(_root_.logger.LogLevel.None)
+ )
+
+ // ******************* Implemented by inlining firrtl.Driver.execute ***************************
+ import firrtl.stage.phases.DriverCompatibility
+ import firrtl.stage.FirrtlStage
+ import firrtl.options.{Dependency, Phase, PhaseManager}
+ import firrtl.options.phases.DeletedWrapper
+
+ val phases: Seq[Phase] = {
+ import DriverCompatibility._
+ new PhaseManager(
+ List(
+ Dependency[AddImplicitFirrtlFile],
+ Dependency[AddImplicitAnnotationFile],
+ Dependency[AddImplicitOutputFile],
+ Dependency[AddImplicitEmitter],
+ Dependency[FirrtlStage]
+ )
+ ).transformOrder
+ .map(DeletedWrapper(_))
}
- firrtl.Driver.execute(optionsManager) match {
- case _: FirrtlExecutionSuccess => true
- case _: FirrtlExecutionFailure => false
+ val annosx =
+ try {
+ phases.foldLeft(annos)((a, p) => p.transform(a))
+ } catch {
+ case _: firrtl.options.OptionsException => return false
+ }
+ // *********************************************************************************************
+
+ val options = annosx
+
+ // ********** Implemented by inlining firrtl.stage.FirrtlExecutionResultView.view **************
+ import firrtl.stage.FirrtlCircuitAnnotation
+
+ options.collectFirst { case a: FirrtlCircuitAnnotation => a.circuit } match {
+ case None => false
+ case Some(_) => true
}
+ // *********************************************************************************************
}
}
-/**
- * This family provides return values from the chisel3 and possibly firrtl compile steps
- */
-@deprecated("This will be removed in Chisel 3.5", "Chisel3 3.4")
-trait ChiselExecutionResult
-
-/**
- *
- * @param circuitOption Optional circuit, has information like circuit name
- * @param emitted The emitted Chirrrl text
- * @param firrtlResultOption Optional Firrtl result, @see freechipsproject/firrtl for details
- */
-@deprecated("This will be removed in Chisel 3.5", "Chisel 3.4")
-case class ChiselExecutionSuccess(
- circuitOption: Option[Circuit],
- emitted: String,
- firrtlResultOption: Option[FirrtlExecutionResult]
- ) extends ChiselExecutionResult
-
-/**
- * Getting one of these indicates failure of some sort.
- *
- * @param message A clue might be provided here.
- */
-@deprecated("This will be removed in Chisel 3.5", "Chisel 3.4")
-case class ChiselExecutionFailure(message: String) extends ChiselExecutionResult
diff --git a/src/main/scala/chisel3/aop/Select.scala b/src/main/scala/chisel3/aop/Select.scala
index 2384c4d3..8f5a2577 100644
--- a/src/main/scala/chisel3/aop/Select.scala
+++ b/src/main/scala/chisel3/aop/Select.scala
@@ -6,10 +6,12 @@ import chisel3._
import chisel3.internal.{HasId}
import chisel3.experimental.BaseModule
import chisel3.experimental.FixedPoint
-import chisel3.internal.firrtl._
+import chisel3.internal.firrtl.{Definition => DefinitionIR, _}
+import chisel3.experimental.hierarchy._
import chisel3.internal.PseudoModule
import chisel3.internal.BaseModule.ModuleClone
import firrtl.annotations.ReferenceTarget
+import scala.reflect.runtime.universe.TypeTag
import scala.collection.mutable
import chisel3.internal.naming.chiselName
@@ -22,7 +24,6 @@ object Select {
/** Return just leaf components of expanded node
*
* @param d Component to find leafs if aggregate typed. Intermediate fields/indicies are not included
- * @return
*/
def getLeafs(d: Data): Seq[Data] = d match {
case r: Record => r.getElements.flatMap(getLeafs)
@@ -33,7 +34,6 @@ object Select {
/** Return all expanded components, including intermediate aggregate nodes
*
* @param d Component to find leafs if aggregate typed. Intermediate fields/indicies ARE included
- * @return
*/
def getIntermediateAndLeafs(d: Data): Seq[Data] = d match {
case r: Record => r +: r.getElements.flatMap(getIntermediateAndLeafs)
@@ -41,15 +41,156 @@ object Select {
case other => Seq(other)
}
+ /** Selects all instances/modules directly instantiated within given definition
+ *
+ * @param parent
+ */
+ def instancesIn(parent: Hierarchy[BaseModule]): Seq[Instance[BaseModule]] = {
+ check(parent)
+ implicit val mg = new chisel3.internal.MacroGenerated{}
+ parent.proto._component.get match {
+ case d: DefModule => d.commands.collect {
+ case d: DefInstance =>
+ d.id match {
+ case p: chisel3.internal.BaseModule.IsClone[_] =>
+ parent._lookup { x => new Instance(Clone(p)).asInstanceOf[Instance[BaseModule]] }
+ case other: BaseModule =>
+ parent._lookup { x => other }
+ }
+ }
+ case other => Nil
+ }
+ }
+
+ /** Selects all Instances of instances/modules directly instantiated within given module, of provided type
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class.
+ * @param parent hierarchy which instantiates the returned Definitions
+ */
+ def instancesOf[T <: BaseModule : TypeTag](parent: Hierarchy[BaseModule]): Seq[Instance[T]] = {
+ check(parent)
+ implicit val mg = new chisel3.internal.MacroGenerated{}
+ parent.proto._component.get match {
+ case d: DefModule => d.commands.flatMap {
+ case d: DefInstance =>
+ d.id match {
+ case p: chisel3.internal.BaseModule.IsClone[_] =>
+ val i = parent._lookup { x => new Instance(Clone(p)).asInstanceOf[Instance[BaseModule]] }
+ if(i.isA[T]) Some(i.asInstanceOf[Instance[T]]) else None
+ case other: BaseModule =>
+ val i = parent._lookup { x => other }
+ if(i.isA[T]) Some(i.asInstanceOf[Instance[T]]) else None
+ }
+ case other => None
+ }
+ case other => Nil
+ }
+ }
+
+ /** Selects all Instances directly and indirectly instantiated within given root hierarchy, of provided type
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class.
+ * @param root top of the hierarchy to search for instances/modules of given type
+ */
+ def allInstancesOf[T <: BaseModule : TypeTag](root: Hierarchy[BaseModule]): Seq[Instance[T]] = {
+ val soFar = if(root.isA[T]) Seq(root.toInstance.asInstanceOf[Instance[T]]) else Nil
+ val allLocalInstances = instancesIn(root)
+ soFar ++ (allLocalInstances.flatMap(allInstancesOf[T]))
+ }
+
+ /** Selects the Definitions of all instances/modules directly instantiated within given module
+ *
+ * @param parent
+ */
+ def definitionsIn(parent: Hierarchy[BaseModule]): Seq[Definition[BaseModule]] = {
+ type DefType = Definition[BaseModule]
+ implicit val mg = new chisel3.internal.MacroGenerated{}
+ check(parent)
+ val defs = parent.proto._component.get match {
+ case d: DefModule => d.commands.collect {
+ case i: DefInstance =>
+ i.id match {
+ case p: chisel3.internal.BaseModule.IsClone[_] =>
+ parent._lookup { x => new Definition(Proto(p.getProto)).asInstanceOf[Definition[BaseModule]] }
+ case other: BaseModule =>
+ parent._lookup { x => other.toDefinition }
+ }
+ }
+ case other => Nil
+ }
+ val (_, defList) = defs.foldLeft((Set.empty[DefType], List.empty[DefType])) { case ((set, list), definition: Definition[BaseModule]) =>
+ if(set.contains(definition)) (set, list) else (set + definition, definition +: list)
+ }
+ defList.reverse
+ }
+
+
+ /** Selects all Definitions of instances/modules directly instantiated within given module, of provided type
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class.
+ * @param parent hierarchy which instantiates the returned Definitions
+ */
+ def definitionsOf[T <: BaseModule : TypeTag](parent: Hierarchy[BaseModule]): Seq[Definition[T]] = {
+ check(parent)
+ implicit val mg = new chisel3.internal.MacroGenerated{}
+ type DefType = Definition[T]
+ val defs = parent.proto._component.get match {
+ case d: DefModule => d.commands.flatMap {
+ case d: DefInstance =>
+ d.id match {
+ case p: chisel3.internal.BaseModule.IsClone[_] =>
+ val d = parent._lookup { x => new Definition(Clone(p)).asInstanceOf[Definition[BaseModule]] }
+ if(d.isA[T]) Some(d.asInstanceOf[Definition[T]]) else None
+ case other: BaseModule =>
+ val d = parent._lookup { x => other.toDefinition }
+ if(d.isA[T]) Some(d.asInstanceOf[Definition[T]]) else None
+ }
+ case other => None
+ }
+ }
+ val (_, defList) = defs.foldLeft((Set.empty[DefType], List.empty[DefType])) { case ((set, list), definition: Definition[T]) =>
+ if(set.contains(definition)) (set, list) else (set + definition, definition +: list)
+ }
+ defList.reverse
+ }
+
+ /** Selects all Definition's directly and indirectly instantiated within given root hierarchy, of provided type
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class, i.e.
+ * a class defined within another class.
+ * @param root top of the hierarchy to search for definitions of given type
+ */
+ def allDefinitionsOf[T <: BaseModule : TypeTag](root: Hierarchy[BaseModule]): Seq[Definition[T]] = {
+ type DefType = Definition[T]
+ val allDefSet = mutable.HashSet[Definition[BaseModule]]()
+ val defSet = mutable.HashSet[DefType]()
+ val defList = mutable.ArrayBuffer[DefType]()
+ def rec(hier: Definition[BaseModule]): Unit = {
+ if(hier.isA[T] && !defSet.contains(hier.asInstanceOf[DefType])) {
+ defSet += hier.asInstanceOf[DefType]
+ defList += hier.asInstanceOf[DefType]
+ }
+ allDefSet += hier
+ val allDefs = definitionsIn(hier)
+ allDefs.collect {
+ case d if !allDefSet.contains(d) => rec(d)
+ }
+ }
+ rec(root.toDefinition)
+ defList.toList
+ }
+
/** Collects all components selected by collector within module and all children modules it instantiates
* directly or indirectly
* Accepts a collector function, rather than a collector partial function (see [[collectDeep]])
+ *
+ * @note This API will not work with the new experimental hierarchy package. Instead, use allInstancesOf or allDefinitionsOf.
+ *
* @param module Module to collect components, as well as all children module it directly and indirectly instantiates
* @param collector Collector function to pick, given a module, which components to collect
* @param tag Required for generics to work, should ignore this
* @tparam T Type of the component that will be collected
- * @return
*/
def getDeep[T](module: BaseModule)(collector: BaseModule => Seq[T]): Seq[T] = {
check(module)
@@ -63,11 +204,13 @@ object Select {
/** Collects all components selected by collector within module and all children modules it instantiates
* directly or indirectly
* Accepts a collector partial function, rather than a collector function (see [[getDeep]])
+ *
+ * @note This API will not work with the new experimental hierarchy package. Instead, use allInstancesOf or allDefinitionsOf.
+ *
* @param module Module to collect components, as well as all children module it directly and indirectly instantiates
* @param collector Collector partial function to pick, given a module, which components to collect
* @param tag Required for generics to work, should ignore this
* @tparam T Type of the component that will be collected
- * @return
*/
def collectDeep[T](module: BaseModule)(collector: PartialFunction[BaseModule, T]): Iterable[T] = {
check(module)
@@ -78,9 +221,11 @@ object Select {
myItems ++ deepChildrenItems
}
- /** Selects all instances directly instantiated within given module
+ /** Selects all modules directly instantiated within given module
+ *
+ * @note This API will not work with the new experimental hierarchy package. Instead, use instancesIn or definitionsIn.
+ *
* @param module
- * @return
*/
def instances(module: BaseModule): Seq[BaseModule] = {
check(module)
@@ -88,7 +233,7 @@ object Select {
case d: DefModule => d.commands.flatMap {
case i: DefInstance => i.id match {
case m: ModuleClone[_] if !m._madeFromDefinition => None
- case _: PseudoModule => throw new Exception("Aspect APIs are currently incompatible with Definition/Instance")
+ case _: PseudoModule => throw new Exception("instances, collectDeep, and getDeep are currently incompatible with Definition/Instance!")
case other => Some(other)
}
case _ => None
@@ -99,7 +244,6 @@ object Select {
/** Selects all registers directly instantiated within given module
* @param module
- * @return
*/
def registers(module: BaseModule): Seq[Data] = {
check(module)
@@ -111,7 +255,6 @@ object Select {
/** Selects all ios directly contained within given module
* @param module
- * @return
*/
def ios(module: BaseModule): Seq[Data] = {
check(module)
@@ -120,7 +263,6 @@ object Select {
/** Selects all SyncReadMems directly contained within given module
* @param module
- * @return
*/
def syncReadMems(module: BaseModule): Seq[SyncReadMem[_]] = {
check(module)
@@ -131,7 +273,6 @@ object Select {
/** Selects all Mems directly contained within given module
* @param module
- * @return
*/
def mems(module: BaseModule): Seq[Mem[_]] = {
check(module)
@@ -142,7 +283,6 @@ object Select {
/** Selects all arithmetic or logical operators directly instantiated within given module
* @param module
- * @return
*/
def ops(module: BaseModule): Seq[(String, Data)] = {
check(module)
@@ -155,7 +295,6 @@ object Select {
* The kind of operators are contained in [[chisel3.internal.firrtl.PrimOp]]
* @param opKind the kind of operator, e.g. "mux", "add", or "bits"
* @param module
- * @return
*/
def ops(opKind: String)(module: BaseModule): Seq[Data] = {
check(module)
@@ -166,7 +305,6 @@ object Select {
/** Selects all wires in a module
* @param module
- * @return
*/
def wires(module: BaseModule): Seq[Data] = {
check(module)
@@ -177,7 +315,6 @@ object Select {
/** Selects all memory ports, including their direction and memory
* @param module
- * @return
*/
def memPorts(module: BaseModule): Seq[(Data, MemPortDirection, MemBase[_])] = {
check(module)
@@ -189,7 +326,6 @@ object Select {
/** Selects all memory ports of a given direction, including their memory
* @param dir The direction of memory ports to select
* @param module
- * @return
*/
def memPorts(dir: MemPortDirection)(module: BaseModule): Seq[(Data, MemBase[_])] = {
check(module)
@@ -200,7 +336,6 @@ object Select {
/** Selects all components who have been set to be invalid, even if they are later connected to
* @param module
- * @return
*/
def invalids(module: BaseModule): Seq[Data] = {
check(module)
@@ -211,7 +346,6 @@ object Select {
/** Selects all components who are attached to a given signal, within a module
* @param module
- * @return
*/
def attachedTo(module: BaseModule)(signal: Data): Set[Data] = {
check(module)
@@ -226,7 +360,6 @@ object Select {
* E.g. if signal = io.foo.bar, connectionsTo will return all connections to io, io.foo, and io.bar
* @param module
* @param signal
- * @return
*/
def connectionsTo(module: BaseModule)(signal: Data): Seq[PredicatedConnect] = {
check(module)
@@ -237,7 +370,7 @@ object Select {
var seenDef = isPort
searchWhens(module, (cmd: Command, preds) => {
cmd match {
- case cmd: Definition if cmd.id.isInstanceOf[Data] =>
+ case cmd: DefinitionIR if cmd.id.isInstanceOf[Data] =>
val x = getIntermediateAndLeafs(cmd.id.asInstanceOf[Data])
if(x.contains(signal)) prePredicates = preds
case Connect(_, loc@Node(d: Data), exp) =>
@@ -263,13 +396,12 @@ object Select {
/** Selects all stop statements, and includes the predicates surrounding the stop statement
*
* @param module
- * @return
*/
def stops(module: BaseModule): Seq[Stop] = {
val stops = mutable.ArrayBuffer[Stop]()
searchWhens(module, (cmd: Command, preds: Seq[Predicate]) => {
cmd match {
- case chisel3.internal.firrtl.Stop(_, clock, ret) => stops += Stop(preds, ret, getId(clock).asInstanceOf[Clock])
+ case chisel3.internal.firrtl.Stop(_, _, clock, ret) => stops += Stop(preds, ret, getId(clock).asInstanceOf[Clock])
case other =>
}
})
@@ -279,7 +411,6 @@ object Select {
/** Selects all printf statements, and includes the predicates surrounding the printf statement
*
* @param module
- * @return
*/
def printfs(module: BaseModule): Seq[Printf] = {
val printfs = mutable.ArrayBuffer[Printf]()
@@ -297,6 +428,7 @@ object Select {
require(module.isClosed, "Can't use Selector on modules that have not finished construction!")
require(module._component.isDefined, "Can't use Selector on modules that don't have components!")
}
+ private def check(hierarchy: Hierarchy[BaseModule]): Unit = check(hierarchy.proto)
// Given a loc, return all subcomponents of id that could be assigned to in connect
private def getEffected(a: Arg): Seq[Data] = a match {
diff --git a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
index 1a476f61..dc7e6487 100644
--- a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
+++ b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
@@ -43,7 +43,7 @@ abstract class InjectorAspect[T <: RawModule, M <: RawModule](
injection: M => Unit
) extends Aspect[T] {
final def toAnnotation(top: T): AnnotationSeq = {
- val moduleNames = Select.collectDeep(top) { case i => i.name }.toSeq
+ val moduleNames = Select.allDefinitionsOf[chisel3.experimental.BaseModule](top.toDefinition).map{i => i.toTarget.module }.toSeq
toAnnotation(selectRoots(top), top.name, moduleNames)
}
diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala
index dde2321d..ccb4ec1f 100644
--- a/src/main/scala/chisel3/compatibility.scala
+++ b/src/main/scala/chisel3/compatibility.scala
@@ -33,7 +33,10 @@ package object Chisel {
implicit class AddDirectionToData[T<:Data](target: T) {
def asInput: T = Input(target)
def asOutput: T = Output(target)
- def flip(): T = Flipped(target)
+ def flip: T = Flipped(target)
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def flip(dummy: Int*): T = flip
}
implicit class AddDirMethodToData[T<:Data](target: T) {
@@ -362,7 +365,8 @@ package object Chisel {
implicit class fromBooleanToLiteral(x: Boolean) extends chisel3.fromBooleanToLiteral(x)
implicit class fromIntToWidth(x: Int) extends chisel3.fromIntToWidth(x)
- type BackendCompilationUtilities = firrtl.util.BackendCompilationUtilities
+ @deprecated("Use object firrtl.util.BackendCompilationUtilities instead", "Chisel 3.5")
+ type BackendCompilationUtilities = chisel3.BackendCompilationUtilities
val ImplicitConversions = chisel3.util.ImplicitConversions
// Deprecated as of Chisel3
@@ -634,6 +638,7 @@ package object Chisel {
final def toUInt(implicit compileOptions: CompileOptions): UInt = a.do_asUInt(DeprecatedSourceInfo, compileOptions)
+ final def toBools(implicit compileOptions: CompileOptions): Seq[Bool] = a.do_asBools(DeprecatedSourceInfo, compileOptions)
}
}
diff --git a/src/main/scala/chisel3/experimental/conversions/package.scala b/src/main/scala/chisel3/experimental/conversions/package.scala
new file mode 100644
index 00000000..574f9f96
--- /dev/null
+++ b/src/main/scala/chisel3/experimental/conversions/package.scala
@@ -0,0 +1,128 @@
+
+package chisel3.experimental
+
+import chisel3._
+import chisel3.experimental.dataview._
+import scala.language.implicitConversions
+
+/** Implicit conversions from some Scala standard library types and [[Data]]
+ *
+ * @note As this leans heavily on the experimental [[DataView]] feature, these APIs are experimental and subject to change
+ */
+package object conversions {
+
+ /** Implicit conversion between `Seq` and `Vec` */
+ implicit def seq2vec[A : DataProduct, B <: Data](xs: Seq[A])(implicit dv: DataView[A, B]): Vec[B] =
+ xs.viewAs[Vec[B]]
+
+ /** Implicit conversion between [[Tuple2]] and [[HWTuple2]] */
+ implicit def tuple2hwtuple[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data](
+ tup: (T1, T2)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2]
+ ): HWTuple2[V1, V2] = {
+ tup.viewAs[HWTuple2[V1, V2]]
+ }
+
+ /** Implicit conversion between [[Tuple3]] and [[HWTuple3]] */
+ implicit def tuple3hwtuple[T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, V1 <: Data, V2 <: Data, V3 <: Data](
+ tup: (T1, T2, T3)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3]
+ ): HWTuple3[V1, V2, V3] = {
+ tup.viewAs[HWTuple3[V1, V2, V3]]
+ }
+
+ /** Implicit conversion between [[Tuple4]] and [[HWTuple4]] */
+ implicit def tuple4hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data
+ ](
+ tup: (T1, T2, T3, T4)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4]
+ ): HWTuple4[V1, V2, V3, V4] = {
+ tup.viewAs[HWTuple4[V1, V2, V3, V4]]
+ }
+
+ /** Implicit conversion between [[Tuple5]] and [[HWTuple5]] */
+ implicit def tuple5hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5]
+ ): HWTuple5[V1, V2, V3, V4, V5] = {
+ tup.viewAs[HWTuple5[V1, V2, V3, V4, V5]]
+ }
+
+ /** Implicit conversion between [[Tuple6]] and [[HWTuple6]] */
+ implicit def tuple6hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, T6 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6]
+ ): HWTuple6[V1, V2, V3, V4, V5, V6] = {
+ tup.viewAs[HWTuple6[V1, V2, V3, V4, V5, V6]]
+ }
+
+ /** Implicit conversion between [[Tuple7]] and [[HWTuple7]] */
+ implicit def tuple7hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6, T7)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6], v7: DataView[T7, V7]
+ ): HWTuple7[V1, V2, V3, V4, V5, V6, V7] = {
+ tup.viewAs[HWTuple7[V1, V2, V3, V4, V5, V6, V7]]
+ }
+
+ /** Implicit conversion between [[Tuple8]] and [[HWTuple8]] */
+ implicit def tuple8hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct, T8 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data, V8 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6, T7, T8)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8]
+ ): HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8] = {
+ tup.viewAs[HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8]]
+ }
+
+ /** Implicit conversion between [[Tuple9]] and [[HWTuple9]] */
+ implicit def tuple9hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6, T7, T8, T9)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8], v9: DataView[T9, V9]
+ ): HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9] = {
+ tup.viewAs[HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9]]
+ }
+
+ /** Implicit conversion between [[Tuple10]] and [[HWTuple10]] */
+ implicit def tuple10hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct, T10 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data, V10 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8], v9: DataView[T9, V9], v10: DataView[T10, V10]
+ ): HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10] = {
+ tup.viewAs[HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10]]
+ }
+}
diff --git a/src/main/scala/chisel3/experimental/verification/package.scala b/src/main/scala/chisel3/experimental/verification/package.scala
new file mode 100644
index 00000000..a026542d
--- /dev/null
+++ b/src/main/scala/chisel3/experimental/verification/package.scala
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.experimental
+
+import chisel3.{Bool, CompileOptions}
+import chisel3.internal.sourceinfo.SourceInfo
+
+package object verification {
+
+ object assert {
+ @deprecated("Please use chisel3.assert instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.5")
+ def apply(predicate: Bool, msg: String = "")
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.assert.Assert = chisel3.assert(predicate, msg)
+ }
+
+ object assume {
+ @deprecated("Please use chisel3.assume instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.5")
+ def apply(predicate: Bool, msg: String = "")
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.assume.Assume = chisel3.assume(predicate, msg)
+ }
+
+ object cover {
+ @deprecated("Please use chisel3.cover instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.5")
+ def apply(predicate: Bool, msg: String = "")
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.cover.Cover = chisel3.cover(predicate, msg)
+ }
+}
diff --git a/src/main/scala/chisel3/stage/package.scala b/src/main/scala/chisel3/stage/package.scala
index 4d6738d6..c307d3ae 100644
--- a/src/main/scala/chisel3/stage/package.scala
+++ b/src/main/scala/chisel3/stage/package.scala
@@ -24,33 +24,4 @@ package object stage {
}
}
-
- private[chisel3] implicit object ChiselExecutionResultView extends OptionsView[ChiselExecutionResult] {
-
- def view(options: AnnotationSeq): ChiselExecutionResult = {
- var chiselCircuit: Option[ChiselCircuit] = None
- var chirrtlCircuit: Option[String] = None
-
- options.foreach {
- case a @ ChiselCircuitAnnotation(b) =>
- chiselCircuit = Some(b)
- chirrtlCircuit = {
- val anno = CircuitSerializationAnnotation(a.circuit, "", FirrtlFileFormat)
- Some(anno.getBytes.map(_.toChar).mkString)
- }
- case _ =>
- }
-
- val fResult = firrtl.stage.phases.DriverCompatibility.firrtlResultView(options)
-
- (chiselCircuit, chirrtlCircuit) match {
- case (None, _) => ChiselExecutionFailure("Failed to elaborate Chisel circuit")
- case (Some(_), None) => ChiselExecutionFailure("Failed to convert Chisel circuit to FIRRTL")
- case (Some(a), Some(b)) => ChiselExecutionSuccess( Some(a), b, Some(fResult))
- }
-
- }
-
- }
-
}
diff --git a/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala b/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala
index 9305c5c9..847b7179 100644
--- a/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala
+++ b/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala
@@ -2,19 +2,13 @@
package chisel3.stage.phases
-import firrtl.{AnnotationSeq, ExecutionOptionsManager, HasFirrtlOptions}
-import firrtl.annotations.NoTargetAnnotation
-import firrtl.options.{Dependency, OptionsException, OutputAnnotationFileAnnotation, Phase, Unserializable}
-import firrtl.stage.{FirrtlCircuitAnnotation, RunFirrtlTransformAnnotation}
-import firrtl.stage.phases.DriverCompatibility.TopNameAnnotation
+import firrtl.annotations.Annotation
+import firrtl.options.Phase
-import chisel3.HasChiselExecutionOptions
-import chisel3.stage.{ChiselStage, NoRunFirrtlCompilerAnnotation, ChiselOutputFileAnnotation}
-
-/** This provides components of a compatibility wrapper around Chisel's deprecated [[chisel3.Driver]].
+/** This formerly provided components of a compatibility wrapper around Chisel's removed `chisel3.Driver`.
*
- * Primarily, this object includes [[firrtl.options.Phase Phase]]s that generate [[firrtl.annotations.Annotation]]s
- * derived from the deprecated [[firrtl.stage.phases.DriverCompatibility.TopNameAnnotation]].
+ * This object formerly included [[firrtl.options.Phase Phase]]s that generate [[firrtl.annotations.Annotation]]s
+ * derived from the deprecated `firrtl.stage.phases.DriverCompatibility.TopNameAnnotation`.
*/
@deprecated("This object contains no public members. This will be removed in Chisel 3.6.", "Chisel 3.5")
object DriverCompatibility
diff --git a/src/main/scala/chisel3/testers/BasicTester.scala b/src/main/scala/chisel3/testers/BasicTester.scala
index d17407ea..99002660 100644
--- a/src/main/scala/chisel3/testers/BasicTester.scala
+++ b/src/main/scala/chisel3/testers/BasicTester.scala
@@ -21,12 +21,7 @@ class BasicTester extends Module() {
* reset). If your definition of reset is not the encapsulating Module's
* reset, you will need to gate this externally.
*/
- def stop()(implicit sourceInfo: SourceInfo) {
- // TODO: rewrite this using library-style SourceInfo passing.
- when (!reset.asBool) {
- pushCommand(Stop(sourceInfo, clock.ref, 0))
- }
- }
+ def stop()(implicit sourceInfo: SourceInfo): Unit = chisel3.stop()
/** The finish method provides a hook that subclasses of BasicTester can use to
* alter a circuit after their constructor has been called.
diff --git a/src/main/scala/chisel3/util/Arbiter.scala b/src/main/scala/chisel3/util/Arbiter.scala
index 059bdd14..b68acae1 100644
--- a/src/main/scala/chisel3/util/Arbiter.scala
+++ b/src/main/scala/chisel3/util/Arbiter.scala
@@ -10,6 +10,7 @@ import chisel3.internal.naming.chiselName // can't use chisel3_ version because
/** IO bundle definition for an Arbiter, which takes some number of ready-valid inputs and outputs
* (selects) at most one.
+ * @groupdesc Signals The actual hardware fields of the Bundle
*
* @param gen data type
* @param n number of inputs
@@ -17,8 +18,20 @@ import chisel3.internal.naming.chiselName // can't use chisel3_ version because
class ArbiterIO[T <: Data](private val gen: T, val n: Int) extends Bundle {
// See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs.
+/** Input data, one per potential sender
+ *
+ * @group Signals
+ */
val in = Flipped(Vec(n, Decoupled(gen)))
+/** Output data after arbitration
+ *
+ * @group Signals
+ */
val out = Decoupled(gen)
+/** One-Hot vector indicating which output was chosen
+ *
+ * @group Signals
+ */
val chosen = Output(UInt(log2Ceil(n).W))
}
@@ -47,7 +60,7 @@ abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLo
val locked = lockCount.value =/= 0.U
val wantsLock = needsLock.map(_(io.out.bits)).getOrElse(true.B)
- when (io.out.fire() && wantsLock) {
+ when (io.out.fire && wantsLock) {
lockIdx := io.chosen
lockCount.inc()
}
@@ -63,7 +76,7 @@ abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLo
class LockingRRArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None)
extends LockingArbiterLike[T](gen, n, count, needsLock) {
- lazy val lastGrant = RegEnable(io.chosen, io.out.fire())
+ lazy val lastGrant = RegEnable(io.chosen, io.out.fire)
lazy val grantMask = (0 until n).map(_.asUInt > lastGrant)
lazy val validMask = io.in zip grantMask map { case (in, g) => in.valid && g }
diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala
index 0dcb2466..808245de 100644
--- a/src/main/scala/chisel3/util/BitPat.scala
+++ b/src/main/scala/chisel3/util/BitPat.scala
@@ -4,11 +4,16 @@ package chisel3.util
import scala.language.experimental.macros
import chisel3._
-import chisel3.internal.chiselRuntimeDeprecated
import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform}
object BitPat {
+
+ private[chisel3] implicit val bitPatOrder = new Ordering[BitPat] {
+ import scala.math.Ordered.orderingToOrdered
+ def compare(x: BitPat, y: BitPat): Int = (x.getWidth, x.value, x.mask) compare (y.getWidth, y.value, y.mask)
+ }
+
/** Parses a bit pattern string into (bits, mask, width).
*
* @return bits the literal value, with don't cares being 0
@@ -90,6 +95,7 @@ object BitPat {
* @note the UInt must be a literal
*/
def apply(x: UInt): BitPat = {
+ require(x.isLit, s"$x is not a literal, BitPat.apply(x: UInt) only accepts literals")
val len = if (x.isWidthKnown) x.getWidth else 0
apply("b" + x.litValue.toString(2).reverse.padTo(len, "0").reverse.mkString)
}
@@ -111,6 +117,119 @@ object BitPat {
}
}
+package experimental {
+ object BitSet {
+
+ /** Construct a [[BitSet]] from a sequence of [[BitPat]].
+ * All [[BitPat]] must have the same width.
+ */
+ def apply(bitpats: BitPat*): BitSet = {
+ val bs = new BitSet { def terms = bitpats.flatMap(_.terms).toSet }
+ // check width
+ bs.getWidth
+ bs
+ }
+
+ /** Empty [[BitSet]]. */
+ val empty: BitSet = new BitSet {
+ def terms = Set()
+ }
+
+ /** Construct a [[BitSet]] from String.
+ * each line should be a valid [[BitPat]] string with the same width.
+ */
+ def fromString(str: String): BitSet = {
+ val bs = new BitSet { def terms = str.split('\n').map(str => BitPat(str)).toSet }
+ // check width
+ bs.getWidth
+ bs
+ }
+ }
+
+ /** A Set of [[BitPat]] represents a set of bit vector with mask. */
+ sealed trait BitSet { outer =>
+ /** all [[BitPat]] elements in [[terms]] make up this [[BitSet]].
+ * all [[terms]] should be have the same width.
+ */
+ def terms: Set[BitPat]
+
+ /** Get specified width of said BitSet */
+ def getWidth: Int = {
+ require(terms.map(_.width).size <= 1, s"All BitPats must be the same size! Got $this")
+ // set width = 0 if terms is empty.
+ terms.headOption.map(_.width).getOrElse(0)
+ }
+
+ import BitPat.bitPatOrder
+ override def toString: String = terms.toSeq.sorted.mkString("\n")
+
+ /** whether this [[BitSet]] is empty (i.e. no value matches) */
+ def isEmpty: Boolean = terms.forall(_.isEmpty)
+
+ /** Check whether this [[BitSet]] overlap with that [[BitSet]], i.e. !(intersect.isEmpty)
+ *
+ * @param that [[BitSet]] to be checked.
+ * @return true if this and that [[BitSet]] have overlap.
+ */
+ def overlap(that: BitSet): Boolean =
+ !terms.flatMap(a => that.terms.map(b => (a, b))).forall { case (a, b) => !a.overlap(b) }
+
+ /** Check whether this [[BitSet]] covers that (i.e. forall b matches that, b also matches this)
+ *
+ * @param that [[BitSet]] to be covered
+ * @return true if this [[BitSet]] can cover that [[BitSet]]
+ */
+ def cover(that: BitSet): Boolean =
+ that.subtract(this).isEmpty
+
+ /** Intersect `this` and `that` [[BitSet]].
+ *
+ * @param that [[BitSet]] to be intersected.
+ * @return a [[BitSet]] containing all elements of `this` that also belong to `that`.
+ */
+ def intersect(that: BitSet): BitSet =
+ terms
+ .flatMap(a => that.terms.map(b => a.intersect(b)))
+ .filterNot(_.isEmpty)
+ .fold(BitSet.empty)(_.union(_))
+
+ /** Subtract that from this [[BitSet]].
+ *
+ * @param that subtrahend [[BitSet]].
+ * @return a [[BitSet]] containing elements of `this` which are not the elements of `that`.
+ */
+ def subtract(that: BitSet): BitSet =
+ terms.map { a =>
+ that.terms.map(b => a.subtract(b)).fold(a)(_.intersect(_))
+ }.filterNot(_.isEmpty).fold(BitSet.empty)(_.union(_))
+
+ /** Union this and that [[BitSet]]
+ *
+ * @param that [[BitSet]] to union.
+ * @return a [[BitSet]] containing all elements of `this` and `that`.
+ */
+ def union(that: BitSet): BitSet = new BitSet {
+ def terms = outer.terms ++ that.terms
+ }
+
+ /** Test whether two [[BitSet]] matches the same set of value
+ *
+ * @note
+ * This method can be very expensive compared to ordinary == operator between two Objects
+ *
+ * @return true if two [[BitSet]] is same.
+ */
+ override def equals(obj: Any): Boolean = {
+ obj match {
+ case that: BitSet => this.getWidth == that.getWidth && this.cover(that) && that.cover(this)
+ case _ => false
+ }
+ }
+ }
+
+}
+
+
/** Bit patterns are literals with masks, used to represent values with don't
* care bits. Equality comparisons will ignore don't care bits.
*
@@ -120,19 +239,19 @@ object BitPat {
* "b10001".U === BitPat("b101??") // evaluates to false.B
* }}}
*/
-sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) extends SourceInfoDoc {
- def getWidth: Int = width
+sealed class BitPat(val value: BigInt, val mask: BigInt, val width: Int) extends util.experimental.BitSet with SourceInfoDoc {
+ import chisel3.util.experimental.BitSet
+ def terms = Set(this)
+
+ /**
+ * Get specified width of said BitPat
+ */
+ override def getWidth: Int = width
def apply(x: Int): BitPat = macro SourceInfoTransform.xArg
def apply(x: Int, y: Int): BitPat = macro SourceInfoTransform.xyArg
def === (that: UInt): Bool = macro SourceInfoTransform.thatArg
def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg
def ## (that: BitPat): BitPat = macro SourceInfoTransform.thatArg
- override def equals(obj: Any): Boolean = {
- obj match {
- case y: BitPat => value == y.value && mask == y.mask && getWidth == y.getWidth
- case _ => false
- }
- }
/** @group SourceInfoTransformMacro */
def do_apply(x: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): BitPat = {
@@ -161,14 +280,83 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) extends Sou
new BitPat((value << that.getWidth) + that.value, (mask << that.getWidth) + that.mask, this.width + that.getWidth)
}
- /** Generate raw string of a BitPat. */
- def rawString: String = Seq.tabulate(width) { i =>
+ /** Check whether this [[BitPat]] overlap with that [[BitPat]], i.e. !(intersect.isEmpty)
+ *
+ * @param that [[BitPat]] to be checked.
+ * @return true if this and that [[BitPat]] have overlap.
+ */
+ def overlap(that: BitPat): Boolean = ((mask & that.mask) & (value ^ that.value)) == 0
+
+ /** Check whether this [[BitSet]] covers that (i.e. forall b matches that, b also matches this)
+ *
+ * @param that [[BitPat]] to be covered
+ * @return true if this [[BitSet]] can cover that [[BitSet]]
+ */
+ def cover(that: BitPat): Boolean = (mask & (~that.mask | (value ^ that.value))) == 0
+
+ /** Intersect `this` and `that` [[BitPat]].
+ *
+ * @param that [[BitPat]] to be intersected.
+ * @return a [[BitSet]] containing all elements of `this` that also belong to `that`.
+ */
+ def intersect(that: BitPat): BitSet = {
+ if (!overlap(that)) {
+ BitSet.empty
+ } else {
+ new BitPat(this.value | that.value, this.mask | that.mask, this.width.max(that.width))
+ }
+ }
+
+ /** Subtract a [[BitPat]] from this.
+ *
+ * @param that subtrahend [[BitPat]].
+ * @return a [[BitSet]] containing elements of `this` which are not the elements of `that`.
+ */
+ def subtract(that: BitPat): BitSet = {
+ require(width == that.width)
+ def enumerateBits(mask: BigInt): Seq[BigInt] = {
+ if (mask == 0) {
+ Nil
+ } else {
+ // bits comes after the first '1' in a number are inverted in its two's complement.
+ // therefore bit is always the first '1' in x (counting from least significant bit).
+ val bit = mask & (-mask)
+ bit +: enumerateBits(mask & ~bit)
+ }
+ }
+
+ val intersection = intersect(that)
+ val omask = this.mask
+ if (intersection.isEmpty) {
+ this
+ } else {
+ new BitSet {
+ val terms =
+ intersection.terms.flatMap { remove =>
+ enumerateBits(~omask & remove.mask).map { bit =>
+ // Only care about higher than current bit in remove
+ val nmask = (omask | ~(bit - 1)) & remove.mask
+ val nvalue = (remove.value ^ bit) & nmask
+ val nwidth = remove.width
+ new BitPat(nvalue, nmask, nwidth)
+ }
+ }
+ }
+ }
+ }
+
+ override def isEmpty: Boolean = false
+
+ /** Generate raw string of a [[BitPat]]. */
+ def rawString: String = Seq
+ .tabulate(width) { i =>
(value.testBit(width - i - 1), mask.testBit(width - i - 1)) match {
- case (true, true) => "1"
- case (false, true) => "0"
- case (_, false) => "?"
+ case (true, true) => "1"
+ case (false, true) => "0"
+ case (_, false) => "?"
+ }
}
- }.mkString
+ .mkString
override def toString = s"BitPat($rawString)"
}
diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala
index 8909ffe3..4b8b3eeb 100644
--- a/src/main/scala/chisel3/util/Decoupled.scala
+++ b/src/main/scala/chisel3/util/Decoupled.scala
@@ -16,6 +16,7 @@ import chisel3.internal.naming._ // can't use chisel3_ version because of compi
* while the consumer uses the flipped interface (inputs bits).
* The actual semantics of ready/valid are enforced via the use of concrete subclasses.
* @param gen the type of data to be wrapped in Ready/Valid
+ * @groupdesc Signals The actual hardware fields of the Bundle
*/
abstract class ReadyValidIO[+T <: Data](gen: T) extends Bundle
{
@@ -26,8 +27,19 @@ abstract class ReadyValidIO[+T <: Data](gen: T) extends Bundle
case _ => gen
}
+/** Indicates that the consumer is ready to accept the data this cycle
+ * @group Signals
+ */
val ready = Input(Bool())
+
+/** Indicates that the producer has put valid data in 'bits'
+ * @group Signals
+ */
val valid = Output(Bool())
+
+/** The data to be transferred when ready and valid are asserted at the same cycle
+ * @group Signals
+ */
val bits = Output(genType)
}
@@ -37,7 +49,10 @@ object ReadyValidIO {
/** Indicates if IO is both ready and valid
*/
- def fire(): Bool = target.ready && target.valid
+ def fire: Bool = target.ready && target.valid
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def fire(dummy: Int = 0): Bool = fire
/** Push dat onto the output bits of this interface to let the consumer know it has happened.
* @param dat the values to assign to bits.
@@ -82,9 +97,6 @@ object ReadyValidIO {
* @param gen the type of data to be wrapped in DecoupledIO
*/
class DecoupledIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen)
-{
- override def cloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type]
-}
/** This factory adds a decoupled handshaking protocol to a data bundle. */
object Decoupled
@@ -121,11 +133,9 @@ object Decoupled
* Additionally, once 'valid' is raised it will never be lowered until after
* 'ready' has also been raised.
* @param gen the type of data to be wrapped in IrrevocableIO
+ * @groupdesc Signals The actual hardware fields of the Bundle
*/
class IrrevocableIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen)
-{
- override def cloneType: this.type = new IrrevocableIO(gen).asInstanceOf[this.type]
-}
/** Factory adds an irrevocable handshaking protocol to a data bundle. */
object Irrevocable
@@ -164,6 +174,7 @@ object DeqIO {
* @param gen The type of data to queue
* @param entries The max number of entries in the queue.
* @param hasFlush A boolean for whether the generated Queue is flushable
+ * @groupdesc Signals The hardware fields of the Bundle
*/
class QueueIO[T <: Data](private val gen: T, val entries: Int, val hasFlush: Boolean = false) extends Bundle
{ // See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs.
@@ -172,13 +183,21 @@ class QueueIO[T <: Data](private val gen: T, val entries: Int, val hasFlush: Boo
* but internally, the queue implementation itself sits on the other side
* of the interface so uses the flipped instance.
*/
- /** I/O to enqueue data (client is producer, and Queue object is consumer), is [[Chisel.DecoupledIO]] flipped. */
+ /** I/O to enqueue data (client is producer, and Queue object is consumer), is [[Chisel.DecoupledIO]] flipped.
+ * @group Signals
+ */
val enq = Flipped(EnqIO(gen))
- /** I/O to dequeue data (client is consumer and Queue object is producer), is [[Chisel.DecoupledIO]]*/
+ /** I/O to dequeue data (client is consumer and Queue object is producer), is [[Chisel.DecoupledIO]]
+ * @group Signals
+ */
val deq = Flipped(DeqIO(gen))
- /** The current amount of data in the queue */
+ /** The current amount of data in the queue
+ * @group Signals
+ */
val count = Output(UInt(log2Ceil(entries + 1).W))
- /** When asserted, reset the enqueue and dequeue pointers, effectively flushing the queue (Optional IO for a flushable Queue)*/
+ /** When asserted, reset the enqueue and dequeue pointers, effectively flushing the queue (Optional IO for a flushable Queue)
+ * @group Signals
+ */
val flush = if (hasFlush) Some(Input(Bool())) else None
}
@@ -228,9 +247,9 @@ class Queue[T <: Data](val gen: T,
val ptr_match = enq_ptr.value === deq_ptr.value
val empty = ptr_match && !maybe_full
val full = ptr_match && maybe_full
- val do_enq = WireDefault(io.enq.fire())
- val do_deq = WireDefault(io.deq.fire())
- val flush = io.flush.getOrElse(false.B)
+ val do_enq = WireDefault(io.enq.fire)
+ val do_deq = WireDefault(io.deq.fire)
+ val flush = io.flush.getOrElse(false.B)
// when flush is high, empty the queue
// Semantically, any enqueues happen before the flush.
@@ -288,20 +307,26 @@ class Queue[T <: Data](val gen: T,
}
}
-/** Factory for a generic hardware queue.
- *
- * @param enq input (enqueue) interface to the queue, also determines width of queue elements
- * @param entries depth (number of elements) of the queue
- *
- * @return output (dequeue) interface from the queue
- *
- * @example {{{
- * consumer.io.in <> Queue(producer.io.out, 16)
- * }}}
- */
+/** Factory for a generic hardware queue. */
object Queue
{
- /** Create a queue and supply a DecoupledIO containing the product. */
+ /** Create a [[Queue]] and supply a [[DecoupledIO]] containing the product.
+ *
+ * @param enq input (enqueue) interface to the queue, also determines type of queue elements.
+ * @param entries depth (number of elements) of the queue
+ * @param pipe True if a single entry queue can run at full throughput (like a pipeline). The `ready` signals are
+ * combinationally coupled.
+ * @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately).
+ * The `valid` signals are coupled.
+ * @param useSyncReadMem True uses SyncReadMem instead of Mem as an internal memory element.
+ * @param flush Optional [[Bool]] signal, if defined, the [[Queue.hasFlush]] will be true, and connect correspond
+ * signal to [[Queue]] instance.
+ * @return output (dequeue) interface from the queue.
+ *
+ * @example {{{
+ * consumer.io.in <> Queue(producer.io.out, 16)
+ * }}}
+ */
@chiselName
def apply[T <: Data](
enq: ReadyValidIO[T],
@@ -309,7 +334,7 @@ object Queue
pipe: Boolean = false,
flow: Boolean = false,
useSyncReadMem: Boolean = false,
- hasFlush: Boolean = false): DecoupledIO[T] = {
+ flush: Option[Bool] = None): DecoupledIO[T] = {
if (entries == 0) {
val deq = Wire(new DecoupledIO(chiselTypeOf(enq.bits)))
deq.valid := enq.valid
@@ -317,7 +342,8 @@ object Queue
enq.ready := deq.ready
deq
} else {
- val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow, useSyncReadMem, hasFlush))
+ val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow, useSyncReadMem, flush.isDefined))
+ q.io.flush.zip(flush).foreach(f => f._1 := f._2)
q.io.enq.valid := enq.valid // not using <> so that override is allowed
q.io.enq.bits := enq.bits
enq.ready := q.io.enq.ready
@@ -325,10 +351,25 @@ object Queue
}
}
- /** Create a queue and supply a IrrevocableIO containing the product.
- * Casting from Decoupled is safe here because we know the Queue has
- * Irrevocable semantics; we didn't want to change the return type of
- * apply() for backwards compatibility reasons.
+ /** Create a queue and supply a [[IrrevocableIO]] containing the product.
+ * Casting from [[DecoupledIO]] is safe here because we know the [[Queue]] has
+ * Irrevocable semantics.
+ * we didn't want to change the return type of apply() for backwards compatibility reasons.
+ *
+ * @param enq [[DecoupledIO]] signal to enqueue.
+ * @param entries The max number of entries in the queue
+ * @param pipe True if a single entry queue can run at full throughput (like a pipeline). The ''ready'' signals are
+ * combinationally coupled.
+ * @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately).
+ * The ''valid'' signals are coupled.
+ * @param useSyncReadMem True uses SyncReadMem instead of Mem as an internal memory element.
+ * @param flush Optional [[Bool]] signal, if defined, the [[Queue.hasFlush]] will be true, and connect correspond
+ * signal to [[Queue]] instance.
+ * @return a [[DecoupledIO]] signal which should connect to the dequeue signal.
+ *
+ * @example {{{
+ * consumer.io.in <> Queue(producer.io.out, 16)
+ * }}}
*/
@chiselName
def irrevocable[T <: Data](
@@ -336,8 +377,9 @@ object Queue
entries: Int = 2,
pipe: Boolean = false,
flow: Boolean = false,
- useSyncReadMem: Boolean = false): IrrevocableIO[T] = {
- val deq = apply(enq, entries, pipe, flow, useSyncReadMem)
+ useSyncReadMem: Boolean = false,
+ flush: Option[Bool] = None): IrrevocableIO[T] = {
+ val deq = apply(enq, entries, pipe, flow, useSyncReadMem, flush)
require(entries > 0, "Zero-entry queues don't guarantee Irrevocability")
val irr = Wire(new IrrevocableIO(chiselTypeOf(deq.bits)))
irr.bits := deq.bits
diff --git a/src/main/scala/chisel3/util/Enum.scala b/src/main/scala/chisel3/util/Enum.scala
index bf150464..4501a2de 100644
--- a/src/main/scala/chisel3/util/Enum.scala
+++ b/src/main/scala/chisel3/util/Enum.scala
@@ -6,7 +6,6 @@
package chisel3.util
import chisel3._
-import chisel3.internal.chiselRuntimeDeprecated
/** Defines a set of unique UInt constants
*
diff --git a/src/main/scala/chisel3/util/Valid.scala b/src/main/scala/chisel3/util/Valid.scala
index 6c6d685e..5d80502a 100644
--- a/src/main/scala/chisel3/util/Valid.scala
+++ b/src/main/scala/chisel3/util/Valid.scala
@@ -17,20 +17,26 @@ import chisel3._
* @tparam T the type of the data
* @param gen some data
* @see [[Valid$ Valid factory]] for concrete examples
+ * @groupdesc Signals The actual hardware fields of the Bundle
*/
class Valid[+T <: Data](gen: T) extends Bundle {
- /** A bit that will be asserted when `bits` is valid */
+ /** A bit that will be asserted when `bits` is valid
+ * @group Signals
+ */
val valid = Output(Bool())
- /** Some data */
+ /** The data to be transferred, qualified by `valid`
+ * @group Signals
+ */
val bits = Output(gen)
/** True when `valid` is asserted
* @return a Chisel [[Bool]] true if `valid` is asserted
*/
- def fire(dummy: Int = 0): Bool = valid
+ def fire: Bool = valid
- override def cloneType: this.type = Valid(gen).asInstanceOf[this.type]
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def fire(dummy: Int = 0): Bool = valid
}
/** Factory for generating "valid" interfaces. A "valid" interface is a data-communicating interface between a producer
@@ -172,13 +178,18 @@ class Pipe[T <: Data](val gen: T, val latency: Int = 1)(implicit compileOptions:
/** Interface for [[Pipe]]s composed of a [[Valid]] input and [[Valid]] output
* @define notAQueue
+ * @groupdesc Signals Hardware fields of the Bundle
*/
class PipeIO extends Bundle {
- /** [[Valid]] input */
+ /** [[Valid]] input
+ * @group Signals
+ */
val enq = Input(Valid(gen))
- /** [[Valid]] output. Data will appear here `latency` cycles after being valid at `enq`. */
+ /** [[Valid]] output. Data will appear here `latency` cycles after being valid at `enq`.
+ * @group Signals
+ */
val deq = Output(Valid(gen))
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
index 1d725875..4dcea99e 100644
--- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
@@ -7,11 +7,21 @@ import logger.LazyLogging
case object EspressoNotFoundException extends Exception
+/** A [[Minimizer]] implementation to use espresso to minimize the [[TruthTable]].
+ *
+ * espresso uses heuristic algorithm providing a sub-optimized) result.
+ * For implementation details, please refer to:
+ * [[https://www.springerprofessional.de/en/logic-minimization-algorithms-for-vlsi-synthesis/13780088]]
+ *
+ * a espresso executable should be downloaded from [[https://github.com/chipsalliance/espresso]]
+ *
+ * If user want to user the this [[Minimizer]], a espresso executable should be added to system PATH environment.
+ */
object EspressoMinimizer extends Minimizer with LazyLogging {
def minimize(table: TruthTable): TruthTable =
TruthTable.merge(TruthTable.split(table).map{case (table, indexes) => (espresso(table), indexes)})
- def espresso(table: TruthTable): TruthTable = {
+ private def espresso(table: TruthTable): TruthTable = {
def writeTable(table: TruthTable): String = {
def invert(string: String) = string
.replace('0', 't')
@@ -45,7 +55,7 @@ object EspressoMinimizer extends Minimizer with LazyLogging {
|""".stripMargin ++ (if (defaultType == '1') invertRawTable else rawTable)
}
- def readTable(espressoTable: String): Map[BitPat, BitPat] = {
+ def readTable(espressoTable: String) = {
def bitPat(espresso: String): BitPat = BitPat("b" + espresso.replace('-', '?'))
espressoTable
@@ -53,7 +63,6 @@ object EspressoMinimizer extends Minimizer with LazyLogging {
.filterNot(_.startsWith("."))
.map(_.split(' '))
.map(row => bitPat(row(0)) -> bitPat(row(1)))
- .toMap
}
val input = writeTable(table)
diff --git a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala
index c1533f44..59120221 100644
--- a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala
@@ -8,6 +8,15 @@ import scala.annotation.tailrec
import scala.math.Ordered.orderingToOrdered
import scala.language.implicitConversions
+/** A [[Minimizer]] implementation to use Quine-Mccluskey algorithm to minimize the [[TruthTable]].
+ *
+ * This algorithm can always find the best solution, but is a NP-Complete algorithm,
+ * which means, for large-scale [[TruthTable]] minimization task, it will be really slow,
+ * and might run out of memory of JVM stack.
+ *
+ * In this situation, users should consider switch to [[EspressoMinimizer]],
+ * which uses heuristic algorithm providing a sub-optimized result.
+ */
object QMCMinimizer extends Minimizer {
private implicit def toImplicant(x: BitPat): Implicant = new Implicant(x)
@@ -225,11 +234,11 @@ object QMCMinimizer extends Minimizer {
val outputBp = BitPat("b" + "?" * (m - i - 1) + "1" + "?" * i)
// Minterms, implicants that makes the output to be 1
- val mint: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && t.value.testBit(i) }.keys.map(toImplicant).toSeq
+ val mint: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && t.value.testBit(i) }.map(_._1).map(toImplicant)
// Maxterms, implicants that makes the output to be 0
- val maxt: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && !t.value.testBit(i) }.keys.map(toImplicant).toSeq
+ val maxt: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && !t.value.testBit(i) }.map(_._1).map(toImplicant)
// Don't cares, implicants that can produce either 0 or 1 as output
- val dc: Seq[Implicant] = table.table.filter { case (_, t) => !t.mask.testBit(i) }.keys.map(toImplicant).toSeq
+ val dc: Seq[Implicant] = table.table.filter { case (_, t) => !t.mask.testBit(i) }.map(_._1).map(toImplicant)
val (implicants, defaultToDc) = table.default match {
case x if x.mask.testBit(i) && !x.value.testBit(i) => // default to 0
@@ -282,7 +291,7 @@ object QMCMinimizer extends Minimizer {
(essentialPrimeImplicants ++ getCover(nonessentialPrimeImplicants, uncoveredImplicants)).map(a => (a.bp, outputBp))
})
- minimized.tail.foldLeft(table.copy(table = Map(minimized.head))) { case (tb, t) =>
+ minimized.tail.foldLeft(table.copy(table = Seq(minimized.head))) { case (tb, t) =>
if (tb.table.exists(x => x._1 == t._1)) {
tb.copy(table = tb.table.map { case (k, v) =>
if (k == t._1) {
@@ -291,7 +300,7 @@ object QMCMinimizer extends Minimizer {
} else (k, v)
})
} else {
- tb.copy(table = tb.table + t)
+ tb.copy(table = tb.table :+ t)
}
}
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
index 683de16b..322466f9 100644
--- a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
@@ -4,8 +4,7 @@ package chisel3.util.experimental.decode
import chisel3.util.BitPat
-final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) {
-
+sealed class TruthTable private (val table: Seq[(BitPat, BitPat)], val default: BitPat, val sort: Boolean) {
def inputWidth = table.head._1.getWidth
def outputWidth = table.head._2.getWidth
@@ -14,10 +13,10 @@ final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) {
def writeRow(map: (BitPat, BitPat)): String =
s"${map._1.rawString}->${map._2.rawString}"
- (table.map(writeRow) ++ Seq(s"${" "*(inputWidth + 2)}${default.rawString}")).toSeq.sorted.mkString("\n")
+ (table.map(writeRow) ++ Seq(s"${" "*(inputWidth + 2)}${default.rawString}")).mkString("\n")
}
- def copy(table: Map[BitPat, BitPat] = this.table, default: BitPat = this.default) = new TruthTable(table, default)
+ def copy(table: Seq[(BitPat, BitPat)] = this.table, default: BitPat = this.default, sort: Boolean = this.sort) = TruthTable(table, default, sort)
override def equals(y: Any): Boolean = {
y match {
@@ -28,25 +27,12 @@ final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) {
}
object TruthTable {
- /** Parse TruthTable from its string representation. */
- def apply(tableString: String): TruthTable = {
- TruthTable(
- tableString
- .split("\n")
- .filter(_.contains("->"))
- .map(_.split("->").map(str => BitPat(s"b$str")))
- .map(bps => bps(0) -> bps(1))
- .toSeq,
- BitPat(s"b${tableString.split("\n").filterNot(_.contains("->")).head.replace(" ", "")}")
- )
- }
-
/** Convert a table and default output into a [[TruthTable]]. */
- def apply(table: Iterable[(BitPat, BitPat)], default: BitPat): TruthTable = {
+ def apply(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = {
require(table.map(_._1.getWidth).toSet.size == 1, "input width not equal.")
require(table.map(_._2.getWidth).toSet.size == 1, "output width not equal.")
val outputWidth = table.map(_._2.getWidth).head
- new TruthTable(table.toSeq.groupBy(_._1.toString).map { case (key, values) =>
+ val mergedTable = table.groupBy(_._1.toString).map { case (key, values) =>
// merge same input inputs.
values.head._1 -> BitPat(s"b${
Seq.tabulate(outputWidth) { i =>
@@ -59,9 +45,23 @@ object TruthTable {
outputSet.headOption.getOrElse('?')
}.mkString
}")
- }, default)
+ }.toSeq
+ import BitPat.bitPatOrder
+ new TruthTable(if(sort) mergedTable.sorted else mergedTable, default, sort)
}
+ /** Parse TruthTable from its string representation. */
+ def fromString(tableString: String): TruthTable = {
+ TruthTable(
+ tableString
+ .split("\n")
+ .filter(_.contains("->"))
+ .map(_.split("->").map(str => BitPat(s"b$str")))
+ .map(bps => bps(0) -> bps(1))
+ .toSeq,
+ BitPat(s"b${tableString.split("\n").filterNot(_.contains("->")).head.replace(" ", "")}")
+ )
+ }
/** consume 1 table, split it into up to 3 tables with the same default bits.
*
@@ -99,18 +99,17 @@ object TruthTable {
tables: Seq[(TruthTable, Seq[Int])]
): TruthTable = {
def reIndex(bitPat: BitPat, table: TruthTable, indexes: Seq[Int]): Seq[(Char, Int)] =
- (table.table.map(a => a._1.toString -> a._2).getOrElse(bitPat.toString, BitPat.dontCare(indexes.size))).rawString.zip(indexes)
+ table.table.map(a => a._1.toString -> a._2).collectFirst{ case (k, v) if k == bitPat.toString => v}.getOrElse(BitPat.dontCare(indexes.size)).rawString.zip(indexes)
def bitPat(indexedChar: Seq[(Char, Int)]) = BitPat(s"b${indexedChar
.sortBy(_._2)
.map(_._1)
.mkString}")
TruthTable(
tables
- .flatMap(_._1.table.keys)
+ .flatMap(_._1.table.map(_._1))
.map { key =>
key -> bitPat(tables.flatMap { case (table, indexes) => reIndex(key, table, indexes) })
- }
- .toMap,
+ },
bitPat(tables.flatMap { case (table, indexes) => table.default.rawString.zip(indexes) })
)
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala
index 42e374d1..e0bf83b2 100644
--- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala
@@ -5,7 +5,7 @@ package chisel3.util.experimental.decode
import chisel3._
import chisel3.experimental.{ChiselAnnotation, annotate}
import chisel3.util.{BitPat, pla}
-import chisel3.util.experimental.getAnnotations
+import chisel3.util.experimental.{BitSet, getAnnotations}
import firrtl.annotations.Annotation
import logger.LazyLogging
@@ -19,7 +19,7 @@ object decoder extends LazyLogging {
*/
def apply(minimizer: Minimizer, input: UInt, truthTable: TruthTable): UInt = {
val minimizedTable = getAnnotations().collect {
- case DecodeTableAnnotation(_, in, out) => TruthTable(in) -> TruthTable(out)
+ case DecodeTableAnnotation(_, in, out) => TruthTable.fromString(in) -> TruthTable.fromString(out)
}.toMap.getOrElse(truthTable, minimizer.minimize(truthTable))
if (minimizedTable.table.isEmpty) {
val outputs = Wire(UInt(minimizedTable.default.getWidth.W))
@@ -80,4 +80,35 @@ object decoder extends LazyLogging {
qmcFallBack(input, truthTable)
}
}
+
+
+ /** Generate a decoder circuit that matches the input to each bitSet.
+ *
+ * The resulting circuit functions like the following but is optimized with a logic minifier.
+ * {{{
+ * when(input === bitSets(0)) { output := b000001 }
+ * .elsewhen (input === bitSets(1)) { output := b000010 }
+ * ....
+ * .otherwise { if (errorBit) output := b100000 else output := DontCare }
+ * }}}
+ *
+ * @param input input to the decoder circuit, width should be equal to bitSets.width
+ * @param bitSets set of ports to be matched, all width should be the equal
+ * @param errorBit whether generate an additional decode error bit at MSB of output.
+ * @return decoded wire
+ */
+ def bitset(input: chisel3.UInt, bitSets: Seq[BitSet], errorBit: Boolean = false): chisel3.UInt =
+ chisel3.util.experimental.decode.decoder(
+ input,
+ chisel3.util.experimental.decode.TruthTable.fromString(
+ {
+ bitSets.zipWithIndex.flatMap {
+ case (bs, i) =>
+ bs.terms.map(bp =>
+ s"${bp.rawString}->${if (errorBit) "0"}${"0" * (bitSets.size - i - 1)}1${"0" * i}"
+ )
+ } ++ Seq(s"${if (errorBit) "1"}${"?" * bitSets.size}")
+ }.mkString("\n")
+ )
+ )
}
diff --git a/src/main/scala/chisel3/util/random/GaloisLFSR.scala b/src/main/scala/chisel3/util/random/GaloisLFSR.scala
index 0d407c87..68346e82 100644
--- a/src/main/scala/chisel3/util/random/GaloisLFSR.scala
+++ b/src/main/scala/chisel3/util/random/GaloisLFSR.scala
@@ -13,7 +13,7 @@ import chisel3._
*
* $seedExplanation
*
- * In the example below, a 4-bit LFSR Fibonacci LFSR is constructed. The tap points are defined as four and three
+ * In the example below, a 4-bit LFSR Galois LFSR is constructed. The tap points are defined as four and three
* (using LFSR convention of indexing from one). This results in the hardware configuration shown in the diagram.
*
* {{{
@@ -85,7 +85,7 @@ class MaxPeriodGaloisLFSR(width: Int, seed: Option[BigInt] = Some(1), reduction:
*/
object GaloisLFSR {
- /** Return a pseudorandom [[UInt]] generated from a [[FibonacciLFSR]].
+ /** Return a pseudorandom [[UInt]] generated from a [[GaloisLFSR]].
* $paramWidth
* $paramTaps
* $paramIncrement
diff --git a/src/main/scala/chisel3/util/random/PRNG.scala b/src/main/scala/chisel3/util/random/PRNG.scala
index d94b78e8..3a44385a 100644
--- a/src/main/scala/chisel3/util/random/PRNG.scala
+++ b/src/main/scala/chisel3/util/random/PRNG.scala
@@ -7,16 +7,23 @@ import chisel3.util.Valid
/** Pseudo Random Number Generators (PRNG) interface
* @param n the width of the LFSR
+ * @groupdesc Signals The actual hardware fields of the Bundle
*/
class PRNGIO(val n: Int) extends Bundle {
- /** A [[chisel3.util.Valid Valid]] interface that can be used to set the seed (internal PRNG state) */
+ /** A [[chisel3.util.Valid Valid]] interface that can be used to set the seed (internal PRNG state)
+ * @group Signals
+ */
val seed: Valid[Vec[Bool]] = Input(Valid(Vec(n, Bool())))
- /** When asserted, the PRNG will increment by one */
+ /** When asserted, the PRNG will increment by one
+ * @group Signals
+ */
val increment: Bool = Input(Bool())
- /** The current state of the PRNG */
+ /** The current state of the PRNG
+ * @group Signals
+ */
val out: Vec[Bool] = Output(Vec(n, Bool()))
}
@@ -62,7 +69,7 @@ abstract class PRNG(val width: Int, val seed: Option[BigInt], step: Int = 1, upd
state := nextState(state)
}
- when (io.seed.fire()) {
+ when (io.seed.fire) {
state := (if (updateSeed) { nextState(io.seed.bits) } else { io.seed.bits })
}
diff --git a/src/test/scala/chisel3/testers/TestUtils.scala b/src/test/scala/chisel3/testers/TestUtils.scala
index c72c779a..338f9cd4 100644
--- a/src/test/scala/chisel3/testers/TestUtils.scala
+++ b/src/test/scala/chisel3/testers/TestUtils.scala
@@ -12,13 +12,4 @@ object TestUtils {
// Useful because TesterDriver.Backend is chisel3 package private
def containsBackend(annos: AnnotationSeq): Boolean =
annos.collectFirst { case b: Backend => b }.isDefined
-
- // Allows us to check that the compiler plugin cloneType is actually working
- val usingPlugin: Boolean = (new Bundle { def check = _usingPlugin }).check
- def elaborateNoReflectiveAutoCloneType(f: => RawModule): Circuit = {
- ChiselStage.elaborate {
- chisel3.internal.Builder.allowReflectiveAutoCloneType = !usingPlugin
- f
- }
- }
}
diff --git a/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
index fcbc4785..ef58f1ed 100644
--- a/src/test/scala/chiselTests/AutoClonetypeSpec.scala
+++ b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
@@ -5,6 +5,7 @@ package chiselTests
import chisel3._
import chisel3.testers.TestUtils
import chisel3.util.QueueIO
+import chisel3.stage.ChiselStage.elaborate
class BundleWithIntArg(val i: Int) extends Bundle {
val out = UInt(i.W)
@@ -71,14 +72,11 @@ class InheritingBundle extends QueueIO(UInt(8.W), 8) {
val error = Output(Bool())
}
-// TODO all `.suggestNames` are due to https://github.com/chipsalliance/chisel3/issues/1802
class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
- val usingPlugin: Boolean = TestUtils.usingPlugin
- val elaborate = TestUtils.elaborateNoReflectiveAutoCloneType _
"Bundles with Scala args" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
val myWire = Wire(new BundleWithIntArg(8))
assert(myWire.i == 8)
@@ -87,7 +85,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
"Bundles with Scala implicit args" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
implicit val implicitInt: Int = 4
val myWire = Wire(new BundleWithImplicit())
@@ -98,7 +96,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
"Bundles with Scala explicit and impicit args" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
implicit val implicitInt: Int = 4
val myWire = Wire(new BundleWithArgAndImplicit(8))
@@ -110,7 +108,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
"Subtyped Bundles" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
val myWire = Wire(new SubBundle(8, 4))
@@ -118,7 +116,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
assert(myWire.i2 == 4)
} }
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
val myWire = Wire(new SubBundleVal(8, 4))
@@ -131,23 +129,12 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
new BundleWithIntArg(8).cloneType
}
- def checkSubBundleInvalid() = {
+ "Subtyped Bundles that don't clone well" should "be now be supported!" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
val myWire = Wire(new SubBundleInvalid(8, 4))
} }
}
- if (usingPlugin) {
- "Subtyped Bundles that don't clone well" should "be now be supported!" in {
- checkSubBundleInvalid()
- }
- } else {
- "Subtyped Bundles that don't clone well" should "be caught" in {
- a [ChiselException] should be thrownBy extractCause[ChiselException] {
- checkSubBundleInvalid()
- }
- }
- }
"Inner bundles with Scala args" should "not need clonetype" in {
elaborate { new ModuleWithInner }
@@ -155,7 +142,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
"Bundles with arguments as fields" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(Output(new BundleWithArgumentField(UInt(8.W), UInt(8.W)))).suggestName("io")
+ val io = IO(Output(new BundleWithArgumentField(UInt(8.W), UInt(8.W))))
io.x := 1.U
io.y := 1.U
} }
@@ -163,28 +150,28 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
it should "also work when giving directions to the fields" in {
elaborate { new Module {
- val io = IO(new BundleWithArgumentField(Input(UInt(8.W)), Output(UInt(8.W)))).suggestName("io")
+ val io = IO(new BundleWithArgumentField(Input(UInt(8.W)), Output(UInt(8.W))))
io.y := io.x
} }
}
"Bundles inside companion objects" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(Output(new CompanionObjectWithBundle.Inner)).suggestName("io")
+ val io = IO(Output(new CompanionObjectWithBundle.Inner))
io.data := 1.U
} }
}
"Parameterized bundles inside companion objects" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(Output(new CompanionObjectWithBundle.ParameterizedInner(8))).suggestName("io")
+ val io = IO(Output(new CompanionObjectWithBundle.ParameterizedInner(8)))
io.data := 1.U
} }
}
"Nested directioned anonymous Bundles" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new NestedAnonymousBundle).suggestName("io")
+ val io = IO(new NestedAnonymousBundle)
val a = WireDefault(io)
io.a.a := 1.U
} }
@@ -197,7 +184,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
val a = Output(UInt(8.W))
}
}
- val io = IO((new InnerClassThing).createBundle).suggestName("io")
+ val io = IO((new InnerClassThing).createBundle)
val a = WireDefault(io)
} }
}
@@ -208,7 +195,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
val bundleFieldType = UInt(8.W)
val io = IO(Output(new Bundle {
val a = bundleFieldType
- })).suggestName("io")
+ }))
io.a := 0.U
} }
}
@@ -221,7 +208,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
}
elaborate { new Module {
- val io = IO(Output(new BadBundle(UInt(8.W), 1))).suggestName("io")
+ val io = IO(Output(new BadBundle(UInt(8.W), 1)))
io.a := 0.U
} }
}
@@ -265,101 +252,97 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
behavior of "Compiler Plugin Autoclonetype"
- // New tests from the plugin
- if (usingPlugin) {
- it should "NOT break code that extends chisel3.util Bundles if they use the plugin" in {
- class MyModule extends MultiIOModule {
- val io = IO(new InheritingBundle)
- io.deq <> io.enq
- io.count := 0.U
- io.error := true.B
- }
- elaborate(new MyModule)
+ it should "NOT break code that extends chisel3.util Bundles if they use the plugin" in {
+ class MyModule extends MultiIOModule {
+ val io = IO(new InheritingBundle)
+ io.deq <> io.enq
+ io.count := 0.U
+ io.error := true.B
}
+ elaborate(new MyModule)
+ }
- it should "support Bundles with non-val parameters" in {
- class MyBundle(i: Int) extends Bundle {
- val foo = UInt(i.W)
- }
- elaborate { new MultiIOModule {
- val in = IO(Input(new MyBundle(8)))
- val out = IO(Output(new MyBundle(8)))
- out := in
- }}
+ it should "support Bundles with non-val parameters" in {
+ class MyBundle(i: Int) extends Bundle {
+ val foo = UInt(i.W)
}
+ elaborate { new MultiIOModule {
+ val in = IO(Input(new MyBundle(8)))
+ val out = IO(Output(new MyBundle(8)))
+ out := in
+ }}
+ }
- it should "support type-parameterized Bundles" in {
- class MyBundle[T <: Data](gen: T) extends Bundle {
- val foo = gen
- }
- elaborate { new MultiIOModule {
- val in = IO(Input(new MyBundle(UInt(8.W))))
- val out = IO(Output(new MyBundle(UInt(8.W))))
- out := in
- }}
+ it should "support type-parameterized Bundles" in {
+ class MyBundle[T <: Data](gen: T) extends Bundle {
+ val foo = gen
}
+ elaborate { new MultiIOModule {
+ val in = IO(Input(new MyBundle(UInt(8.W))))
+ val out = IO(Output(new MyBundle(UInt(8.W))))
+ out := in
+ }}
+ }
- it should "support Bundles with non-val implicit parameters" in {
- class MyBundle(implicit i: Int) extends Bundle {
- val foo = UInt(i.W)
- }
- elaborate { new MultiIOModule {
- implicit val x = 8
- val in = IO(Input(new MyBundle))
- val out = IO(Output(new MyBundle))
- out := in
- }}
+ it should "support Bundles with non-val implicit parameters" in {
+ class MyBundle(implicit i: Int) extends Bundle {
+ val foo = UInt(i.W)
}
+ elaborate { new MultiIOModule {
+ implicit val x = 8
+ val in = IO(Input(new MyBundle))
+ val out = IO(Output(new MyBundle))
+ out := in
+ }}
+ }
- it should "support Bundles with multiple parameter lists" in {
- class MyBundle(i: Int)(j: Int, jj: Int)(k: UInt) extends Bundle {
- val foo = UInt((i + j + jj + k.getWidth).W)
- }
- elaborate {
- new MultiIOModule {
- val in = IO(Input(new MyBundle(8)(8, 8)(UInt(8.W))))
- val out = IO(Output(new MyBundle(8)(8, 8)(UInt(8.W))))
- out := in
- }
+ it should "support Bundles with multiple parameter lists" in {
+ class MyBundle(i: Int)(j: Int, jj: Int)(k: UInt) extends Bundle {
+ val foo = UInt((i + j + jj + k.getWidth).W)
+ }
+ elaborate {
+ new MultiIOModule {
+ val in = IO(Input(new MyBundle(8)(8, 8)(UInt(8.W))))
+ val out = IO(Output(new MyBundle(8)(8, 8)(UInt(8.W))))
+ out := in
}
}
+ }
- it should "support Bundles that implement their own cloneType" in {
- class MyBundle(i: Int) extends Bundle {
- val foo = UInt(i.W)
- override def cloneType = new MyBundle(i).asInstanceOf[this.type]
- }
- elaborate { new MultiIOModule {
- val in = IO(Input(new MyBundle(8)))
- val out = IO(Output(new MyBundle(8)))
- out := in
- }}
+ it should "support Bundles that implement their own cloneType" in {
+ class MyBundle(i: Int) extends Bundle {
+ val foo = UInt(i.W)
}
+ elaborate { new MultiIOModule {
+ val in = IO(Input(new MyBundle(8)))
+ val out = IO(Output(new MyBundle(8)))
+ out := in
+ }}
+ }
- it should "support Bundles that capture type parameters from their parent scope" in {
- class MyModule[T <: Data](gen: T) extends MultiIOModule {
- class MyBundle(n: Int) extends Bundle {
- val foo = Vec(n, gen)
- }
- val in = IO(Input(new MyBundle(4)))
- val out = IO(Output(new MyBundle(4)))
- out := in
+ it should "support Bundles that capture type parameters from their parent scope" in {
+ class MyModule[T <: Data](gen: T) extends MultiIOModule {
+ class MyBundle(n: Int) extends Bundle {
+ val foo = Vec(n, gen)
}
- elaborate(new MyModule(UInt(8.W)))
+ val in = IO(Input(new MyBundle(4)))
+ val out = IO(Output(new MyBundle(4)))
+ out := in
}
+ elaborate(new MyModule(UInt(8.W)))
+ }
- it should "work for higher-kinded types" in {
- class DataGen[T <: Data](gen: T) {
- def newType: T = gen.cloneType
- }
- class MyBundle[A <: Data, B <: DataGen[A]](gen: B) extends Bundle {
- val foo = gen.newType
- }
- class MyModule extends MultiIOModule {
- val io = IO(Output(new MyBundle[UInt, DataGen[UInt]](new DataGen(UInt(3.W)))))
- io.foo := 0.U
- }
- elaborate(new MyModule)
+ it should "work for higher-kinded types" in {
+ class DataGen[T <: Data](gen: T) {
+ def newType: T = gen.cloneType
+ }
+ class MyBundle[A <: Data, B <: DataGen[A]](gen: B) extends Bundle {
+ val foo = gen.newType
+ }
+ class MyModule extends MultiIOModule {
+ val io = IO(Output(new MyBundle[UInt, DataGen[UInt]](new DataGen(UInt(3.W)))))
+ io.foo := 0.U
}
+ elaborate(new MyModule)
}
}
diff --git a/src/test/scala/chiselTests/AutoNestedCloneSpec.scala b/src/test/scala/chiselTests/AutoNestedCloneSpec.scala
index 401766e2..258d0823 100644
--- a/src/test/scala/chiselTests/AutoNestedCloneSpec.scala
+++ b/src/test/scala/chiselTests/AutoNestedCloneSpec.scala
@@ -3,6 +3,7 @@
package chiselTests
import chisel3._
import chisel3.testers.TestUtils
+import chisel3.stage.ChiselStage.elaborate
import org.scalatest.matchers.should.Matchers
class BundleWithAnonymousInner(val w: Int) extends Bundle {
@@ -11,10 +12,7 @@ class BundleWithAnonymousInner(val w: Int) extends Bundle {
}
}
-// TODO all `.suggestNames` are due to https://github.com/chipsalliance/chisel3/issues/1802
class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
- val usingPlugin: Boolean = TestUtils.usingPlugin
- val elaborate = TestUtils.elaborateNoReflectiveAutoCloneType _
behavior of "autoCloneType of inner Bundle in Chisel3"
@@ -27,7 +25,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
}
def getIO: InnerIOType = new InnerIOType
}
- val io = IO(new Bundle {}).suggestName("io")
+ val io = IO(new Bundle {})
val myWire = Wire((new Middle(w)).getIO)
}
new Outer(2)
@@ -37,7 +35,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
it should "clone an anonymous inner bundle successfully" in {
elaborate {
class TestTop(val w: Int) extends Module {
- val io = IO(new Bundle {}).suggestName("io")
+ val io = IO(new Bundle {})
val myWire = Wire(new Bundle{ val a = UInt(w.W) })
}
new TestTop(2)
@@ -50,13 +48,13 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
val io = IO(new Bundle{
val in = Input(UInt(w.W))
val out = Output(UInt(w.W))
- }).suggestName("io")
+ })
}
class Outer(val w: Int) extends Module {
val io = IO(new Bundle{
val in = Input(UInt(w.W))
val out = Output(UInt(w.W))
- }).suggestName("io")
+ })
val i = Module(new Inner(w))
val iw = Wire(chiselTypeOf(i.io))
iw <> io
@@ -69,7 +67,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
it should "clone an anonymous, bound, inner bundle of another bundle successfully" in {
elaborate {
class TestModule(w: Int) extends Module {
- val io = IO(new BundleWithAnonymousInner(w) ).suggestName("io")
+ val io = IO(new BundleWithAnonymousInner(w))
val w0 = WireDefault(io)
val w1 = WireDefault(io.inner)
}
@@ -85,7 +83,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
}
val io = IO(new Bundle {
val inner = Input(bun)
- }).suggestName("io")
+ })
val w0 = WireDefault(io)
val w1 = WireDefault(io.inner)
}
@@ -100,42 +98,39 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
val inner = Input(new Bundle {
val x = UInt(8.W)
})
- }).suggestName("io")
+ })
}
new TestModule()
}
}
- if (usingPlugin) {
- // This works with the plugin, but is a null pointer exception when using reflective autoclonetype
- it should "support an anonymous doubly-nested inner bundle" in {
- elaborate {
- class Outer(val w: Int) extends Module {
- class Middle(val w: Int) {
- def getIO: Bundle = new Bundle {
- val in = Input(UInt(w.W))
- }
+ it should "support an anonymous doubly-nested inner bundle" in {
+ elaborate {
+ class Outer(val w: Int) extends Module {
+ class Middle(val w: Int) {
+ def getIO: Bundle = new Bundle {
+ val in = Input(UInt(w.W))
}
- val io = IO(new Bundle {}).suggestName("io")
- val myWire = Wire((new Middle(w)).getIO)
}
- new Outer(2)
+ val io = IO(new Bundle {})
+ val myWire = Wire((new Middle(w)).getIO)
}
+ new Outer(2)
}
+ }
- it should "support anonymous Inner bundles that capture type parameters from outer Bundles" in {
- elaborate(new MultiIOModule {
- class MyBundle[T <: Data](n: Int, gen: T) extends Bundle {
- val foo = new Bundle {
- val x = Input(Vec(n, gen))
- }
- val bar = Output(Option(new { def mkBundle = new Bundle { val x = Vec(n, gen) }}).get.mkBundle)
+ it should "support anonymous Inner bundles that capture type parameters from outer Bundles" in {
+ elaborate(new MultiIOModule {
+ class MyBundle[T <: Data](n: Int, gen: T) extends Bundle {
+ val foo = new Bundle {
+ val x = Input(Vec(n, gen))
}
- val io = IO(new MyBundle(4, UInt(8.W)))
- val myWire = WireInit(io.foo)
- val myWire2 = WireInit(io.bar)
- io.bar.x := io.foo.x
- })
- }
+ val bar = Output(Option(new { def mkBundle = new Bundle { val x = Vec(n, gen) }}).get.mkBundle)
+ }
+ val io = IO(new MyBundle(4, UInt(8.W)))
+ val myWire = WireInit(io.foo)
+ val myWire2 = WireInit(io.bar)
+ io.bar.x := io.foo.x
+ })
}
}
diff --git a/src/test/scala/chiselTests/BlackBoxImpl.scala b/src/test/scala/chiselTests/BlackBoxImpl.scala
index a9a6fa29..2fa3d8a6 100644
--- a/src/test/scala/chiselTests/BlackBoxImpl.scala
+++ b/src/test/scala/chiselTests/BlackBoxImpl.scala
@@ -7,7 +7,6 @@ import java.io.File
import chisel3._
import chisel3.util.{HasBlackBoxInline, HasBlackBoxResource, HasBlackBoxPath}
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
-import firrtl.FirrtlExecutionSuccess
import firrtl.transforms.BlackBoxNotFoundException
import org.scalacheck.Test.Failed
import org.scalatest.Succeeded
diff --git a/src/test/scala/chiselTests/BundleSpec.scala b/src/test/scala/chiselTests/BundleSpec.scala
index 1d392f5c..d9f82e6d 100644
--- a/src/test/scala/chiselTests/BundleSpec.scala
+++ b/src/test/scala/chiselTests/BundleSpec.scala
@@ -10,25 +10,20 @@ trait BundleSpecUtils {
class BundleFooBar extends Bundle {
val foo = UInt(16.W)
val bar = UInt(16.W)
- override def cloneType: this.type = (new BundleFooBar).asInstanceOf[this.type]
}
class BundleBarFoo extends Bundle {
val bar = UInt(16.W)
val foo = UInt(16.W)
- override def cloneType: this.type = (new BundleBarFoo).asInstanceOf[this.type]
}
class BundleFoo extends Bundle {
val foo = UInt(16.W)
- override def cloneType: this.type = (new BundleFoo).asInstanceOf[this.type]
}
class BundleBar extends Bundle {
val bar = UInt(16.W)
- override def cloneType: this.type = (new BundleBar).asInstanceOf[this.type]
}
class BadSeqBundle extends Bundle {
val bar = Seq(UInt(16.W), UInt(8.W), UInt(4.W))
- override def cloneType: this.type = (new BadSeqBundle).asInstanceOf[this.type]
}
class MyModule(output: Bundle, input: Bundle) extends Module {
@@ -116,17 +111,21 @@ class BundleSpec extends ChiselFlatSpec with BundleSpecUtils with Utils {
}
}
- "Bundles" should "not have aliased fields" in {
+ "Bundles" should "with aliased fields, should show a helpful error message" in {
+ class AliasedBundle extends Bundle {
+ val a = UInt(8.W)
+ val b = a
+ val c = SInt(8.W)
+ val d = c
+ }
+
(the[ChiselException] thrownBy extractCause[ChiselException] {
ChiselStage.elaborate { new Module {
- val io = IO(Output(new Bundle {
- val a = UInt(8.W)
- val b = a
- }))
+ val io = IO(Output(new AliasedBundle))
io.a := 0.U
io.b := 1.U
} }
- }).getMessage should include("aliased fields")
+ }).getMessage should include("contains aliased fields named (a,b),(c,d)")
}
"Bundles" should "not have bound hardware" in {
@@ -162,4 +161,16 @@ class BundleSpec extends ChiselFlatSpec with BundleSpecUtils with Utils {
}
}
}
+
+ // This tests the interaction of override def cloneType and the plugin.
+ // We are commenting it for now because although this code fails to compile
+ // as expected when just copied here, the test version is not seeing the failure.
+ // """
+ // class BundleBaz(w: Int) extends Bundle {
+ // val baz = UInt(w.W)
+ // // This is a compiler error when using the plugin, which we test below.
+ // override def cloneType = (new BundleBaz(w)).asInstanceOf[this.type]
+ // }
+ // """ shouldNot compile
+
}
diff --git a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
index 1795cc1f..4b03dfa5 100644
--- a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
+++ b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
@@ -12,8 +12,6 @@ object CompatibilityComponents {
class ChiselBundle extends Bundle {
val a = UInt(width = 32)
val b = UInt(width = 32).flip
-
- override def cloneType: this.type = (new ChiselBundle).asInstanceOf[this.type]
}
class ChiselRecord extends Record {
val elements = ListMap("a" -> UInt(width = 32), "b" -> UInt(width = 32).flip)
@@ -48,8 +46,6 @@ object Chisel3Components {
class Chisel3Bundle extends Bundle {
val a = Output(UInt(32.W))
val b = Input(UInt(32.W))
-
- override def cloneType: this.type = (new Chisel3Bundle).asInstanceOf[this.type]
}
class Chisel3Record extends Record {
@@ -341,7 +337,6 @@ class CompatibiltyInteroperabilitySpec extends ChiselFlatSpec {
val foo = maybeFlip(new Bundle {
val bar = UInt(INPUT, width = 8)
})
- override def cloneType = (new MyBundle(extraFlip)).asInstanceOf[this.type]
}
}
import chisel3._
diff --git a/src/test/scala/chiselTests/CompatibilitySpec.scala b/src/test/scala/chiselTests/CompatibilitySpec.scala
index 2d4ad517..7ac67b7c 100644
--- a/src/test/scala/chiselTests/CompatibilitySpec.scala
+++ b/src/test/scala/chiselTests/CompatibilitySpec.scala
@@ -195,11 +195,9 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck
class SmallBundle extends Bundle {
val f1 = UInt(width = 4)
val f2 = UInt(width = 5)
- override def cloneType: this.type = (new SmallBundle).asInstanceOf[this.type]
}
class BigBundle extends SmallBundle {
val f3 = UInt(width = 6)
- override def cloneType: this.type = (new BigBundle).asInstanceOf[this.type]
}
"A Module with missing bundle fields when compiled with the Chisel compatibility package" should "not throw an exception" in {
@@ -538,6 +536,9 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck
info("toUInt works")
s.toUInt shouldBe a [UInt]
+
+ info("toBools works")
+ s.toBools shouldBe a [Seq[Bool]]
}
ChiselStage.elaborate(new Foo)
@@ -566,4 +567,32 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck
verilog should include ("assign io_out_0 = io_in_0;")
}
+ it should "ignore .suggestName on field io" in {
+ class MyModule extends Module {
+ val io = new Bundle {
+ val foo = UInt(width = 8).asInput
+ val bar = UInt(width = 8).asOutput
+ }
+ io.suggestName("potato")
+ io.bar := io.foo
+ }
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("input [7:0] io_foo")
+ verilog should include ("output [7:0] io_bar")
+ }
+
+ it should "properly name field io" in {
+ class MyModule extends Module {
+ val io = new Bundle {
+ val foo = UInt(width = 8).asInput
+ val bar = UInt(width = 8).asOutput
+ }
+ val wire = Wire(init = io.foo)
+ io.bar := wire
+ }
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("input [7:0] io_foo")
+ verilog should include ("output [7:0] io_bar")
+ }
+
}
diff --git a/src/test/scala/chiselTests/CompileOptionsTest.scala b/src/test/scala/chiselTests/CompileOptionsTest.scala
index 9c88c1e0..1ecf97f0 100644
--- a/src/test/scala/chiselTests/CompileOptionsTest.scala
+++ b/src/test/scala/chiselTests/CompileOptionsTest.scala
@@ -14,11 +14,9 @@ class CompileOptionsSpec extends ChiselFlatSpec with Utils {
class SmallBundle extends Bundle {
val f1 = UInt(4.W)
val f2 = UInt(5.W)
- override def cloneType: this.type = (new SmallBundle).asInstanceOf[this.type]
}
class BigBundle extends SmallBundle {
val f3 = UInt(6.W)
- override def cloneType: this.type = (new BigBundle).asInstanceOf[this.type]
}
"A Module with missing bundle fields when compiled with implicit Strict.CompileOption " should "throw an exception" in {
diff --git a/src/test/scala/chiselTests/ComplexAssign.scala b/src/test/scala/chiselTests/ComplexAssign.scala
index 36fb59c2..222b6373 100644
--- a/src/test/scala/chiselTests/ComplexAssign.scala
+++ b/src/test/scala/chiselTests/ComplexAssign.scala
@@ -7,10 +7,7 @@ import chisel3.testers.BasicTester
import chisel3.util._
import org.scalacheck.Shrink
-class Complex[T <: Data](val re: T, val im: T) extends Bundle {
- override def cloneType: this.type =
- new Complex(re.cloneType, im.cloneType).asInstanceOf[this.type]
-}
+class Complex[T <: Data](val re: T, val im: T) extends Bundle
class ComplexAssign(w: Int) extends Module {
val io = IO(new Bundle {
diff --git a/src/test/scala/chiselTests/ConnectSpec.scala b/src/test/scala/chiselTests/ConnectSpec.scala
index 367864e6..f9ef5946 100644
--- a/src/test/scala/chiselTests/ConnectSpec.scala
+++ b/src/test/scala/chiselTests/ConnectSpec.scala
@@ -2,6 +2,8 @@
package chiselTests
+import org.scalatest._
+
import chisel3._
import chisel3.experimental.{Analog, FixedPoint}
import chisel3.stage.ChiselStage
@@ -126,4 +128,37 @@ class ConnectSpec extends ChiselPropSpec with Utils {
property("Pipe internal connections should succeed") {
ChiselStage.elaborate( new PipeInternalWires)
}
+
+ property("Connect error messages should have meaningful information") {
+ class InnerExample extends Module {
+ val myReg = RegInit(0.U(8.W))
+ }
+
+ class OuterAssignExample extends Module {
+ val inner = Module(new InnerExample())
+ inner.myReg := false.B // ERROR
+ }
+
+ val assignError = the [ChiselException] thrownBy {ChiselStage.elaborate { new OuterAssignExample}}
+ val expectedAssignError = """.*@: myReg in InnerExample cannot be written from module OuterAssignExample."""
+ assignError.getMessage should fullyMatch regex expectedAssignError
+
+ class OuterReadExample extends Module {
+ val myReg = RegInit(0.U(8.W))
+ val inner = Module(new InnerExample())
+ myReg := inner.myReg // ERROR
+ }
+
+ val readError = the [ChiselException] thrownBy {ChiselStage.elaborate { new OuterReadExample }}
+ val expectedReadError = """.*@: myReg in InnerExample cannot be read from module OuterReadExample."""
+ readError.getMessage should fullyMatch regex expectedReadError
+
+ val typeMismatchError = the [ChiselException] thrownBy {ChiselStage.elaborate { new RawModule {
+ val myUInt = Wire(UInt(4.W))
+ val mySInt = Wire(SInt(4.W))
+ myUInt := mySInt
+ }}}
+ val expectedTypeMismatchError = """.*@: Sink \(UInt<4>\) and Source \(SInt<4>\) have different types."""
+ typeMismatchError.getMessage should fullyMatch regex expectedTypeMismatchError
+ }
}
diff --git a/src/test/scala/chiselTests/DataPrint.scala b/src/test/scala/chiselTests/DataPrint.scala
index b5f96c4d..7fb790a8 100644
--- a/src/test/scala/chiselTests/DataPrint.scala
+++ b/src/test/scala/chiselTests/DataPrint.scala
@@ -20,6 +20,14 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {
val b = Bool()
}
+ class PartialBundleTest extends Bundle {
+ val a = UInt(8.W)
+ val b = Bool()
+ val c = SInt(8.W)
+ val e = FixedPoint(5.W, 3.BP)
+ val f = EnumTest.Type()
+ }
+
"Data types" should "have a meaningful string representation" in {
ChiselStage.elaborate { new RawModule {
UInt().toString should be ("UInt")
@@ -31,18 +39,20 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {
Vec(3, UInt(2.W)).toString should be ("UInt<2>[3]")
EnumTest.Type().toString should be ("EnumTest")
(new BundleTest).toString should be ("BundleTest")
- } }
+ new Bundle { val a = UInt(8.W) }.toString should be ("AnonymousBundle")
+ new Bundle { val a = UInt(8.W) }.a.toString should be ("UInt<8>")
+ }}
}
class BoundDataModule extends Module { // not in the test to avoid anon naming suffixes
- Wire(UInt()).toString should be("UInt(Wire in BoundDataModule)")
- Reg(SInt()).toString should be("SInt(Reg in BoundDataModule)")
+ Wire(UInt()).toString should be("BoundDataModule.?: Wire[UInt]")
+ Reg(SInt()).toString should be("BoundDataModule.?: Reg[SInt]")
val io = IO(Output(Bool())) // needs a name so elaboration doesn't fail
- io.toString should be("Bool(IO in unelaborated BoundDataModule)")
+ io.toString should be("BoundDataModule.io: IO[Bool]")
val m = Mem(4, UInt(2.W))
- m(2).toString should be("UInt<2>(MemPort in BoundDataModule)")
- (2.U + 2.U).toString should be("UInt<2>(OpResult in BoundDataModule)")
- Wire(Vec(3, UInt(2.W))).toString should be ("UInt<2>[3](Wire in BoundDataModule)")
+ m(2).toString should be("BoundDataModule.?: MemPort[UInt<2>]")
+ (2.U + 2.U).toString should be("BoundDataModule.?: OpResult[UInt<2>]")
+ Wire(Vec(3, UInt(2.W))).toString should be ("BoundDataModule.?: Wire[UInt<2>[3]]")
class InnerModule extends Module {
val io = IO(Output(new Bundle {
@@ -50,8 +60,31 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {
}))
}
val inner = Module(new InnerModule)
- inner.clock.toString should be ("Clock(IO clock in InnerModule)")
- inner.io.a.toString should be ("UInt<4>(IO io_a in InnerModule)")
+ inner.clock.toString should be ("InnerModule.clock: IO[Clock]")
+ inner.io.a.toString should be ("InnerModule.io.a: IO[UInt<4>]")
+
+ class FooTypeTest extends Bundle {
+ val foo = Vec(2, UInt(8.W))
+ val fizz = UInt(8.W)
+ }
+ val tpe = new FooTypeTest
+ val fooio: FooTypeTest = IO(Input(tpe))
+ fooio.foo(0).toString should be ("BoundDataModule.fooio.foo[0]: IO[UInt<8>]")
+
+ class NestedBundle extends Bundle {
+ val nestedFoo = UInt(8.W)
+ val nestedFooVec = Vec(2, UInt(8.W))
+ }
+ class NestedType extends Bundle {
+ val foo = new NestedBundle
+ }
+
+ val nestedTpe = new NestedType
+ val nestedio = IO(Input(nestedTpe))
+ (nestedio.foo.nestedFoo.toString should be
+ ("BoundDataModule.nestedio.foo.nestedFoo: IO[UInt<8>]"))
+ (nestedio.foo.nestedFooVec(0).toString should be
+ ("BoundDataModule.nestedio.foo.nestedFooVec[0]: IO[UInt<8>]"))
}
"Bound data types" should "have a meaningful string representation" in {
@@ -67,13 +100,12 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {
true.B.toString should be ("Bool(true)")
2.25.F(6.W, 2.BP).toString should be ("FixedPoint<6><<2>>(2.25)")
-2.25.F(6.W, 2.BP).toString should be ("FixedPoint<6><<2>>(-2.25)")
+ Vec(3, UInt(4.W)).toString should be ("UInt<4>[3]")
EnumTest.sNone.toString should be ("EnumTest(0=sNone)")
EnumTest.sTwo.toString should be ("EnumTest(2=sTwo)")
EnumTest(1.U).toString should be ("EnumTest(1=sOne)")
(new BundleTest).Lit(_.a -> 2.U, _.b -> false.B).toString should be ("BundleTest(a=UInt<8>(2), b=Bool(false))")
- new Bundle {
- val a = UInt(8.W)
- }.toString should be ("AnonymousBundle")
+ (new PartialBundleTest).Lit().toString should be ("PartialBundleTest(a=UInt<8>(DontCare), b=Bool(DontCare), c=SInt<8>(DontCare), e=FixedPoint<5><<3>>(DontCare), f=EnumTest(DontCare))")
DontCare.toString should be ("DontCare()")
} }
}
diff --git a/src/test/scala/chiselTests/FixedPointSpec.scala b/src/test/scala/chiselTests/FixedPointSpec.scala
index a1acdb17..2530bb13 100644
--- a/src/test/scala/chiselTests/FixedPointSpec.scala
+++ b/src/test/scala/chiselTests/FixedPointSpec.scala
@@ -60,6 +60,9 @@ class FixedPointFromBitsTester extends BasicTester {
val negativefp = (-3.5).F(4.BP)
val positivefp = 3.5.F(4.BP)
+ assert(- positivefp === negativefp)
+ assert(positivefp === -negativefp)
+
assert(uint2fp === uint_result)
assert(sint2fp === sint_result)
assert(fp2fp === fp_result)
diff --git a/src/test/scala/chiselTests/Harness.scala b/src/test/scala/chiselTests/Harness.scala
index 23379498..51576566 100644
--- a/src/test/scala/chiselTests/Harness.scala
+++ b/src/test/scala/chiselTests/Harness.scala
@@ -4,10 +4,7 @@ package chiselTests
import java.io.File
-import firrtl.util.BackendCompilationUtilities
-
-class HarnessSpec extends ChiselPropSpec
- with BackendCompilationUtilities {
+class HarnessSpec extends ChiselPropSpec {
def makeTrivialVerilog: (File => File) = makeHarness((prefix: String) => s"""
module ${prefix};
diff --git a/src/test/scala/chiselTests/InlineSpec.scala b/src/test/scala/chiselTests/InlineSpec.scala
index 397eac2e..59a1e984 100644
--- a/src/test/scala/chiselTests/InlineSpec.scala
+++ b/src/test/scala/chiselTests/InlineSpec.scala
@@ -5,7 +5,6 @@ package chiselTests
import chisel3._
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util.experimental.{InlineInstance, FlattenInstance}
-import firrtl.FirrtlExecutionSuccess
import firrtl.passes.InlineAnnotation
import firrtl.stage.{FirrtlCircuitAnnotation, FirrtlStage}
import firrtl.transforms.FlattenAnnotation
diff --git a/src/test/scala/chiselTests/IntervalSpec.scala b/src/test/scala/chiselTests/IntervalSpec.scala
index abc619e5..c223260d 100644
--- a/src/test/scala/chiselTests/IntervalSpec.scala
+++ b/src/test/scala/chiselTests/IntervalSpec.scala
@@ -15,7 +15,7 @@ import firrtl.passes.CheckTypes.InvalidConnect
import firrtl.passes.CheckWidths.{DisjointSqueeze, InvalidRange}
import firrtl.passes.{PassExceptions, WrapWithRemainder}
import firrtl.stage.{CompilerAnnotation, FirrtlCircuitAnnotation}
-import firrtl.{FIRRTLException, HighFirrtlCompiler, LowFirrtlCompiler, MiddleFirrtlCompiler, MinimumVerilogCompiler, NoneCompiler, SystemVerilogCompiler, VerilogCompiler}
+import firrtl.{HighFirrtlCompiler, LowFirrtlCompiler, MiddleFirrtlCompiler, MinimumVerilogCompiler, NoneCompiler, SystemVerilogCompiler, VerilogCompiler}
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers
@@ -406,6 +406,13 @@ class IntervalChainedSubTester extends BasicTester {
assert(intervalResult1 === 5.I)
assert(intervalResult2 === 5.I)
+ val negativeInterval = (-3.5).I(4.BP)
+ val positiveInterval = 3.5.I(4.BP)
+
+ assert(negativeInterval =/= positiveInterval)
+ assert(-negativeInterval === positiveInterval)
+ assert(negativeInterval === -positiveInterval)
+
stop()
}
diff --git a/src/test/scala/chiselTests/InvalidateAPISpec.scala b/src/test/scala/chiselTests/InvalidateAPISpec.scala
index b7db33cc..52ad02b4 100644
--- a/src/test/scala/chiselTests/InvalidateAPISpec.scala
+++ b/src/test/scala/chiselTests/InvalidateAPISpec.scala
@@ -105,7 +105,7 @@ class InvalidateAPISpec extends ChiselPropSpec with Matchers with BackendCompila
ChiselStage.elaborate(new ModuleWithDontCareSink)
}
}
- exception.getMessage should include("DontCare cannot be a connection sink (LHS)")
+ exception.getMessage should include("DontCare cannot be a connection sink")
}
property("a DontCare cannot be a connection sink (LHS) for <>") {
diff --git a/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala b/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala
index 8a998496..74e587bc 100644
--- a/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala
+++ b/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala
@@ -8,7 +8,6 @@ import chisel3._
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util.experimental.{loadMemoryFromFile,loadMemoryFromFileInline}
import chisel3.util.log2Ceil
-import firrtl.FirrtlExecutionSuccess
import firrtl.annotations.MemoryLoadFileType
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers
diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala
index 7703e876..f0d6dbe7 100644
--- a/src/test/scala/chiselTests/Module.scala
+++ b/src/test/scala/chiselTests/Module.scala
@@ -9,6 +9,7 @@ import firrtl.annotations.NoTargetAnnotation
import firrtl.options.Unserializable
import scala.io.Source
+import scala.annotation.nowarn
class SimpleIO extends Bundle {
val in = Input(UInt(32.W))
@@ -167,6 +168,71 @@ class ModuleSpec extends ChiselPropSpec with Utils {
"a" -> m.a, "b" -> m.b))
})
}
+
+ property("DataMirror.modulePorts should replace deprecated <module>.getPorts") {
+ class MyModule extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(Vec(2, UInt(8.W)))
+ })
+ val extra = IO(Input(UInt(8.W)))
+ val delay = RegNext(io.in)
+ io.out(0) := delay
+ io.out(1) := delay + extra
+ }
+ var mod: MyModule = null
+ ChiselStage.elaborate {
+ mod = new MyModule
+ mod
+ }
+ // Note that this is just top-level ports, Aggregates are not flattened
+ DataMirror.modulePorts(mod) should contain theSameElementsInOrderAs Seq(
+ "clock" -> mod.clock,
+ "reset" -> mod.reset,
+ "io" -> mod.io,
+ "extra" -> mod.extra
+ )
+ // Delete this when the deprecated API is deleted
+ // Note this also uses deprecated Port
+ import chisel3.internal.firrtl.Port
+ import SpecifiedDirection.{Input => IN, Unspecified}
+ mod.getPorts should contain theSameElementsInOrderAs Seq(
+ Port(mod.clock, IN),
+ Port(mod.reset, IN),
+ Port(mod.io, Unspecified),
+ Port(mod.extra, IN)
+ ): @nowarn // delete when Port and getPorts become private
+ }
+
+ property("DataMirror.fullModulePorts should return all ports including children of Aggregates") {
+ class MyModule extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(Vec(2, UInt(8.W)))
+ })
+ val extra = IO(Input(UInt(8.W)))
+ val delay = RegNext(io.in)
+ io.out(0) := delay
+ io.out(1) := delay + extra
+ }
+ var mod: MyModule = null
+ ChiselStage.elaborate {
+ mod = new MyModule
+ mod
+ }
+ val expected = Seq(
+ "clock" -> mod.clock,
+ "reset" -> mod.reset,
+ "io" -> mod.io,
+ "io_out" -> mod.io.out,
+ "io_out_0" -> mod.io.out(0),
+ "io_out_1" -> mod.io.out(1),
+ "io_in" -> mod.io.in,
+ "extra" -> mod.extra
+ )
+ DataMirror.fullModulePorts(mod) should contain theSameElementsInOrderAs expected
+ }
+
property("A desiredName parameterized by a submodule should work") {
ChiselStage.elaborate(new ModuleWrapper(new ModuleWire)).name should be ("ModuleWireWrapper")
}
diff --git a/src/test/scala/chiselTests/PrintableSpec.scala b/src/test/scala/chiselTests/PrintableSpec.scala
index 25b54966..c7e819ec 100644
--- a/src/test/scala/chiselTests/PrintableSpec.scala
+++ b/src/test/scala/chiselTests/PrintableSpec.scala
@@ -3,7 +3,7 @@
package chiselTests
import chisel3._
-import chisel3.experimental.{BaseSim, ChiselAnnotation}
+import chisel3.experimental.ChiselAnnotation
import chisel3.stage.ChiselStage
import chisel3.testers.BasicTester
import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation}
@@ -23,7 +23,7 @@ object PrintfAnnotation {
/** Create annotation for a given [[printf]].
* @param c component to be annotated
*/
- def annotate(c: BaseSim): Unit = {
+ def annotate(c: VerificationStatement): Unit = {
chisel3.experimental.annotate(new ChiselAnnotation {
def toFirrtl: PrintfAnnotation = PrintfAnnotation(c.toTarget)
})
@@ -139,7 +139,6 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
}
class MyBundle extends Bundle {
val foo = UInt(32.W)
- override def cloneType: this.type = (new MyBundle).asInstanceOf[this.type]
}
class MyModule extends BasicTester {
override def desiredName: String = "MyModule"
@@ -246,7 +245,7 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
// check for expected annotations
exactly(3, annoLines) should include ("chiselTests.PrintfAnnotation")
exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>farewell")
- exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>SIM")
+ exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>printf")
exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>howdy")
// read in FIRRTL file
@@ -256,7 +255,7 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
// check that verification components have expected names
exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "hello AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : howdy""")
- exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "goodbye AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : SIM""")
+ exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "goodbye AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : printf""")
exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "adieu AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : farewell""")
}
}
diff --git a/src/test/scala/chiselTests/QueueFlushSpec.scala b/src/test/scala/chiselTests/QueueFlushSpec.scala
index 11a411a8..9e0c6bb4 100644
--- a/src/test/scala/chiselTests/QueueFlushSpec.scala
+++ b/src/test/scala/chiselTests/QueueFlushSpec.scala
@@ -40,11 +40,11 @@ abstract class FlushQueueTesterBase(elements: Seq[Int], queueDepth: Int, bitWidt
q.io.deq.ready := LFSR(16)(tap)
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
currQCnt := currQCnt + 1.U //counts how many items have been enqueued
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
assert(flushRegister === false.B) //check queue isn't flushed (can't dequeue an empty queue)
}
when(flushRegister) { //Internal signal maybe_full is a register so some signals update on the next cycle
@@ -70,18 +70,18 @@ class QueueGetsFlushedTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int,
flush := LFSR(16)((tap + 3) % 16) //testing a flush when flush is called randomly
val halfCnt = (queueDepth + 1)/2
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//ensure that what comes out is what comes in
assert(currQCnt <= queueDepth.U)
assert(elems(outCnt) === q.io.deq.bits)
outCnt := outCnt + 1.U
when (currQCnt > 0.U) {
- currQCnt := Mux(q.io.enq.fire(), currQCnt, (currQCnt - 1.U))
+ currQCnt := Mux(q.io.enq.fire, currQCnt, (currQCnt - 1.U))
}
}
when(flush) {
assert(currQCnt === 0.U || q.io.deq.valid)
- outCnt := outCnt + Mux(q.io.enq.fire(), (currQCnt + 1.U), currQCnt)
+ outCnt := outCnt + Mux(q.io.enq.fire, (currQCnt + 1.U), currQCnt)
currQCnt := 0.U //resets the number of items currently inside queue
}
}
@@ -102,7 +102,7 @@ class EmptyFlushEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWidth: I
flush := (cycleCounter.value === 0.U && inCnt.value === 0.U) //flushed only before anything is enqueued
q.io.enq.valid := (inCnt.value < elements.length.U) && !flush
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
assert(elems(outCnt) === q.io.deq.bits)
outCnt := outCnt + 1.U
}
@@ -124,7 +124,7 @@ class EnqueueEmptyFlushEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitW
flush := (cycleCounter.value === 0.U && inCnt.value === 0.U) //flushed only before anything is enqueued
cycleCounter.inc() //counts every cycle
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//flush and enqueue were both active on the first cycle,
//so that element is flushed immediately which makes outCnt off by one
assert(elems(outCounter.value + 1.U) === q.io.deq.bits) //ensure that what comes out is what comes in
@@ -145,7 +145,7 @@ class FullQueueFlushEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWidt
//testing a flush when queue is full
flush := (currQCnt === queueDepth.U)
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//ensure that what comes out is what comes in
assert(currQCnt <= queueDepth.U)
assert(elems(outCnt) === q.io.deq.bits)
@@ -177,7 +177,7 @@ class DequeueFullQueueEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWi
q.io.enq.valid := !flushRegister
q.io.deq.ready := flush
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//ensure that what comes out is what comes in
assert(currQCnt <= queueDepth.U)
assert(elems(outCnt) === q.io.deq.bits)
@@ -191,7 +191,7 @@ class DequeueFullQueueEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWi
}
when(flushRegister) {
//check that queue gets flushed when queue is full
- assert(q.io.deq.fire() === false.B)
+ assert(q.io.deq.fire === false.B)
}
}
diff --git a/src/test/scala/chiselTests/QueueSpec.scala b/src/test/scala/chiselTests/QueueSpec.scala
index 51b899cb..9eb6c20c 100644
--- a/src/test/scala/chiselTests/QueueSpec.scala
+++ b/src/test/scala/chiselTests/QueueSpec.scala
@@ -21,10 +21,10 @@ class ThingsPassThroughTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int
q.io.deq.ready := LFSR(16)(tap)
q.io.flush.foreach { _ := false.B } //Flush behavior is tested in QueueFlushSpec
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//ensure that what comes out is what comes in
assert(elems(outCnt.value) === q.io.deq.bits)
outCnt.inc()
@@ -51,10 +51,10 @@ class QueueReasonableReadyValid(elements: Seq[Int], queueDepth: Int, bitWidth: I
assert(q.io.deq.valid || q.io.count === 0.U)
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
}
when(outCnt.value === elements.length.U) {
@@ -74,11 +74,11 @@ class CountIsCorrectTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, t
q.io.deq.ready := LFSR(16)(tap)
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
assert(q.io.count === (inCnt.value - outCnt.value))
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
assert(q.io.count === (inCnt.value - outCnt.value))
}
@@ -103,10 +103,10 @@ class QueueSinglePipeTester(elements: Seq[Int], bitWidth: Int, tap: Int, useSync
assert(q.io.enq.ready || (q.io.count === 1.U && !q.io.deq.ready))
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
}
@@ -129,10 +129,10 @@ class QueuePipeTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: I
assert(q.io.enq.ready || (q.io.count === queueDepth.U && !q.io.deq.ready))
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
}
@@ -155,13 +155,13 @@ class QueueFlowTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: I
q.io.deq.ready := LFSR(16)(tap)
//Queue should be empty or valid
- assert(q.io.deq.valid || (q.io.count === 0.U && !q.io.enq.fire()))
+ assert(q.io.deq.valid || (q.io.count === 0.U && !q.io.enq.fire))
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
}
when(outCnt.value === elements.length.U) {
@@ -183,10 +183,10 @@ class QueueFactoryTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap
deq.ready := LFSR(16)(tap)
enq.bits := elems(inCnt.value)
- when(enq.fire()) {
+ when(enq.fire) {
inCnt.inc()
}
- when(deq.fire()) {
+ when(deq.fire) {
//ensure that what comes out is what comes in
assert(elems(outCnt.value) === deq.bits)
outCnt.inc()
diff --git a/src/test/scala/chiselTests/RecordSpec.scala b/src/test/scala/chiselTests/RecordSpec.scala
index c21d455c..e6986efb 100644
--- a/src/test/scala/chiselTests/RecordSpec.scala
+++ b/src/test/scala/chiselTests/RecordSpec.scala
@@ -8,11 +8,12 @@ import chisel3.testers.BasicTester
import chisel3.util.{Counter, Queue}
import chisel3.experimental.DataMirror
+import scala.collection.immutable.SeqMap
+
trait RecordSpecUtils {
class MyBundle extends Bundle {
val foo = UInt(32.W)
val bar = UInt(32.W)
- override def cloneType: this.type = (new MyBundle).asInstanceOf[this.type]
}
// Useful for constructing types from CustomBundle
// This is a def because each call to this needs to return a new instance
@@ -65,6 +66,11 @@ trait RecordSpecUtils {
}
}
+ class AliasedRecord extends Module {
+ val field = UInt(32.W)
+ val io = IO(new CustomBundle("in" -> Input(field), "out" -> Output(field)))
+ }
+
class RecordIOModule extends Module {
val io = IO(new CustomBundle("in" -> Input(UInt(32.W)), "out" -> Output(UInt(32.W))))
io("out") := io("in")
@@ -104,6 +110,23 @@ class RecordSpec extends ChiselFlatSpec with RecordSpecUtils with Utils {
ChiselStage.elaborate { new MyModule(new MyBundle, fooBarType) }
}
+ they should "not allow aliased fields" in {
+ class AliasedFieldRecord extends Record {
+ val foo = UInt(8.W)
+ val elements = SeqMap("foo" -> foo, "bar" -> foo)
+ override def cloneType: AliasedFieldRecord.this.type = this
+ }
+
+ val e = intercept[AliasedAggregateFieldException] {
+ ChiselStage.elaborate {
+ new Module {
+ val io = IO(new AliasedFieldRecord)
+ }
+ }
+ }
+ e.getMessage should include ("contains aliased fields named (bar,foo)")
+ }
+
they should "follow UInt serialization/deserialization API" in {
assertTesterPasses { new RecordSerializationTest }
}
diff --git a/src/test/scala/chiselTests/SIntOps.scala b/src/test/scala/chiselTests/SIntOps.scala
index f2e238e9..222d0ba7 100644
--- a/src/test/scala/chiselTests/SIntOps.scala
+++ b/src/test/scala/chiselTests/SIntOps.scala
@@ -44,7 +44,7 @@ class SIntOps extends Module {
io.noteqout := (a =/= b)
io.lesseqout := a <= b
io.greateqout := a >= b
- // io.negout := -a(15, 0).toSInt
+ io.negout := -a(15, 0).asSInt
io.negout := (0.S -% a)
}
diff --git a/src/test/scala/chiselTests/StrongEnum.scala b/src/test/scala/chiselTests/StrongEnum.scala
index d7dea571..404c3f66 100644
--- a/src/test/scala/chiselTests/StrongEnum.scala
+++ b/src/test/scala/chiselTests/StrongEnum.scala
@@ -257,8 +257,8 @@ class IsLitTester extends BasicTester {
for (e <- EnumExample.all) {
val wire = WireDefault(e)
- assert(e.isLit())
- assert(!wire.isLit())
+ assert(e.isLit)
+ assert(!wire.isLit)
}
stop()
}
diff --git a/src/test/scala/chiselTests/TransitNameSpec.scala b/src/test/scala/chiselTests/TransitNameSpec.scala
index b21818d6..656c6731 100644
--- a/src/test/scala/chiselTests/TransitNameSpec.scala
+++ b/src/test/scala/chiselTests/TransitNameSpec.scala
@@ -6,7 +6,6 @@ import chisel3._
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util.TransitName
-import firrtl.FirrtlExecutionSuccess
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
diff --git a/src/test/scala/chiselTests/UIntOps.scala b/src/test/scala/chiselTests/UIntOps.scala
index 62d00de2..bc6454b8 100644
--- a/src/test/scala/chiselTests/UIntOps.scala
+++ b/src/test/scala/chiselTests/UIntOps.scala
@@ -6,6 +6,7 @@ import chisel3._
import org.scalatest._
import chisel3.stage.ChiselStage
import chisel3.testers.BasicTester
+import chisel3.util._
import org.scalacheck.Shrink
import org.scalatest.matchers.should.Matchers
@@ -22,6 +23,8 @@ class UIntOps extends Module {
val modout = Output(UInt(32.W))
val lshiftout = Output(UInt(32.W))
val rshiftout = Output(UInt(32.W))
+ val lrotateout = Output(UInt(32.W))
+ val rrotateout = Output(UInt(32.W))
val lessout = Output(Bool())
val greatout = Output(Bool())
val eqout = Output(Bool())
@@ -30,6 +33,8 @@ class UIntOps extends Module {
val greateqout = Output(Bool())
})
+ dontTouch(io)
+
val a = io.a
val b = io.b
@@ -42,6 +47,8 @@ class UIntOps extends Module {
io.modout := a % b
io.lshiftout := (a << b(3, 0))(31, 0)
io.rshiftout := a >> b
+ io.lrotateout := a.rotateLeft(5)
+ io.rrotateout := a.rotateRight(5)
io.lessout := a < b
io.greatout := a > b
io.eqout := a === b
@@ -67,6 +74,14 @@ class UIntOpsTester(a: Long, b: Long) extends BasicTester {
assert(dut.io.modout === (a % (b max 1)).U(32.W))
assert(dut.io.lshiftout === (a << (b % 16)).U(32.W))
assert(dut.io.rshiftout === (a >> b).U(32.W))
+ assert(
+ dut.io.lrotateout === s"h${Integer.rotateLeft(a.toInt, 5).toHexString}"
+ .U(32.W)
+ )
+ assert(
+ dut.io.rrotateout === s"h${Integer.rotateRight(a.toInt, 5).toHexString}"
+ .U(32.W)
+ )
assert(dut.io.lessout === (a < b).B)
assert(dut.io.greatout === (a > b).B)
assert(dut.io.eqout === (a == b).B)
@@ -98,6 +113,65 @@ class NegativeShift(t: => Bits) extends Module {
Reg(t) >> -1
}
+class BasicRotate extends BasicTester {
+ val shiftAmount = random.LFSR(4)
+ val ctr = RegInit(0.U(4.W))
+
+
+ val rotL = 1.U(3.W).rotateLeft(shiftAmount)
+ val rotR = 1.U(3.W).rotateRight(shiftAmount)
+
+ printf("Shift amount: %d rotateLeft:%b rotateRight:%b\n", shiftAmount, rotL, rotR)
+
+ switch(shiftAmount % 3.U) {
+ is(0.U, 3.U) {
+ assert(rotL === "b001".U)
+ assert(rotR === "b001".U)
+ }
+ is(1.U) {
+ assert(rotL === "b010".U)
+ assert(rotR === "b100".U)
+ }
+ is(2.U) {
+ assert(rotL === "b100".U)
+ assert(rotR === "b010".U)
+ }
+ }
+
+ ctr := ctr + 1.U
+
+ when (ctr === 15.U){
+ stop()
+ }
+}
+
+/** rotating a w-bit word left by n should be equivalent to rotating it by w - n
+ * to the left
+ */
+class MatchedRotateLeftAndRight(w: Int = 13) extends BasicTester {
+ val initValue = BigInt(w, scala.util.Random)
+ println(s"Initial value: ${initValue.toString(2)}")
+
+ val maxWidthBits = log2Ceil(w + 1)
+ val shiftAmount1 = RegInit(0.U(w.W))
+ val shiftAmount2 = RegInit(w.U(w.W))
+ shiftAmount1 := shiftAmount1 + 1.U
+ shiftAmount2 := shiftAmount2 - 1.U
+
+ val value = RegInit(initValue.U(w.W))
+
+ val out1 = value.rotateLeft(shiftAmount1)
+ val out2 = value.rotateRight(shiftAmount2)
+
+ printf("rotateLeft by %d: %b\n", shiftAmount1, out1)
+
+ assert(out1 === out2)
+ when(shiftAmount1 === w.U) {
+ assert(out1 === initValue.U)
+ stop()
+ }
+}
+
class UIntLitExtractTester extends BasicTester {
assert("b101010".U(2) === false.B)
assert("b101010".U(3) === true.B)
@@ -140,6 +214,16 @@ class UIntOpsSpec extends ChiselPropSpec with Matchers with Utils {
}
}
+ property("rotateLeft and rotateRight should work for dynamic shift values") {
+ assertTesterPasses(new BasicRotate)
+ }
+
+ property(
+ "rotateLeft and rotateRight should be consistent for dynamic shift values"
+ ) {
+ assertTesterPasses(new MatchedRotateLeftAndRight)
+ }
+
property("Bit extraction on literals should work for all non-negative indices") {
assertTesterPasses(new UIntLitExtractTester)
}
diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala
index 97aea909..24ba0bf8 100644
--- a/src/test/scala/chiselTests/Vec.scala
+++ b/src/test/scala/chiselTests/Vec.scala
@@ -313,6 +313,36 @@ class ModuleIODynamicIndexTester(n: Int) extends BasicTester {
when (done) { stop() }
}
+class ReduceTreeTester() extends BasicTester {
+ class FooIO[T <: Data](n: Int, private val gen: T) extends Bundle {
+ val in = Flipped(Vec(n, new DecoupledIO(gen)))
+ val out = new DecoupledIO(gen)
+ }
+
+ class Foo[T <: Data](n: Int, private val gen: T) extends Module {
+ val io = IO(new FooIO(n, gen))
+
+ def foo(a: DecoupledIO[T], b: DecoupledIO[T]) = {
+ a.ready := true.B
+ b.ready := true.B
+ val out = Wire(new DecoupledIO(gen))
+
+ out.valid := true.B
+
+ val regSel = RegInit(false.B)
+ out.bits := Mux(regSel, a.bits, b.bits)
+ out.ready := a.ready
+ out
+ }
+
+ io.out <> io.in.reduceTree(foo)
+ }
+
+ val dut = Module(new Foo(5, UInt(5.W)))
+ dut.io := DontCare
+ stop()
+}
+
class VecSpec extends ChiselPropSpec with Utils {
// Disable shrinking on error.
implicit val noShrinkListVal = Shrink[List[Int]](_ => Stream.empty)
@@ -456,4 +486,8 @@ class VecSpec extends ChiselPropSpec with Utils {
}}
}
}
+
+ property("reduceTree should preserve input/output type") {
+ assertTesterPasses { new ReduceTreeTester() }
+ }
}
diff --git a/src/test/scala/chiselTests/VecLiteralSpec.scala b/src/test/scala/chiselTests/VecLiteralSpec.scala
index d91cd2f4..74d8c005 100644
--- a/src/test/scala/chiselTests/VecLiteralSpec.scala
+++ b/src/test/scala/chiselTests/VecLiteralSpec.scala
@@ -142,17 +142,17 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
"lowest of vec literal contains least significant bits and " in {
val y = Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 1 -> 0xCD.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W))
- y.litValue() should be(BigInt("FFEFCDAB", 16))
+ y.litValue should be(BigInt("FFEFCDAB", 16))
}
"the order lits are specified does not matter" in {
val y = Vec(4, UInt(8.W)).Lit(3 -> 0xFF.U(8.W), 2 -> 0xEF.U(8.W), 1 -> 0xCD.U(8.W), 0 -> 0xAB.U(8.W))
- y.litValue() should be(BigInt("FFEFCDAB", 16))
+ y.litValue should be(BigInt("FFEFCDAB", 16))
}
"regardless of the literals widths, packing should be done based on the width of the Vec's gen" in {
val z = Vec(4, UInt(8.W)).Lit(0 -> 0x2.U, 1 -> 0x2.U, 2 -> 0x2.U, 3 -> 0x3.U)
- z.litValue() should be(BigInt("03020202", 16))
+ z.litValue should be(BigInt("03020202", 16))
}
"packing sparse vec lits should not pack, litOption returns None" in {
@@ -221,7 +221,7 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
chisel3.assert(outsideVecLit(2) === 0xBB.U)
chisel3.assert(outsideVecLit(3) === 0xAA.U)
- chisel3.assert(outsideVecLit.litValue().U === outsideVecLit.asUInt())
+ chisel3.assert(outsideVecLit.litValue.U === outsideVecLit.asUInt())
val insideVecLit = Vec(4, UInt(16.W)).Lit(0 -> 0xDD.U, 1 -> 0xCC.U, 2 -> 0xBB.U, 3 -> 0xAA.U)
chisel3.assert(insideVecLit(0) === 0xDD.U)
@@ -277,15 +277,15 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
1 -> Vec(3, UInt(4.W)).Lit(0 -> 4.U, 1 -> 5.U, 2 -> 6.U)
)
- outerVec.litValue() should be (BigInt("654321", 16))
- outerVec(0).litValue() should be (BigInt("321", 16))
- outerVec(1).litValue() should be (BigInt("654", 16))
- outerVec(0)(0).litValue() should be (BigInt(1))
- outerVec(0)(1).litValue() should be (BigInt(2))
- outerVec(0)(2).litValue() should be (BigInt(3))
- outerVec(1)(0).litValue() should be (BigInt(4))
- outerVec(1)(1).litValue() should be (BigInt(5))
- outerVec(1)(2).litValue() should be (BigInt(6))
+ outerVec.litValue should be (BigInt("654321", 16))
+ outerVec(0).litValue should be (BigInt("321", 16))
+ outerVec(1).litValue should be (BigInt("654", 16))
+ outerVec(0)(0).litValue should be (BigInt(1))
+ outerVec(0)(1).litValue should be (BigInt(2))
+ outerVec(0)(2).litValue should be (BigInt(3))
+ outerVec(1)(0).litValue should be (BigInt(4))
+ outerVec(1)(1).litValue should be (BigInt(5))
+ outerVec(1)(2).litValue should be (BigInt(6))
}
"contained vecs should work" in {
@@ -473,19 +473,19 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
0 -> (new SubBundle).Lit(_.foo -> 0xab.U, _.bar -> 0xc.U),
1 -> (new SubBundle).Lit(_.foo -> 0xde.U, _.bar -> 0xf.U)
)
- vec.litValue().toString(16) should be("defabc")
+ vec.litValue.toString(16) should be("defabc")
}
"vec literals can have bundle children assembled incrementally" in {
val bundle1 = (new SubBundle).Lit(_.foo -> 0xab.U, _.bar -> 0xc.U)
val bundle2 = (new SubBundle).Lit(_.foo -> 0xde.U, _.bar -> 0xf.U)
- bundle1.litValue().toString(16) should be("abc")
- bundle2.litValue().toString(16) should be("def")
+ bundle1.litValue.toString(16) should be("abc")
+ bundle2.litValue.toString(16) should be("def")
val vec = Vec(2, new SubBundle).Lit(0 -> bundle1, 1 -> bundle2)
- vec.litValue().toString(16) should be("defabc")
+ vec.litValue.toString(16) should be("defabc")
}
"bundles can contain vec lits" in {
@@ -495,7 +495,7 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
val foo = Vec(3, UInt(4.W))
val bar = Vec(2, UInt(4.W))
}).Lit(_.foo -> vec1, _.bar -> vec2)
- bundle.litValue().toString(16) should be("cbaed")
+ bundle.litValue.toString(16) should be("cbaed")
}
"bundles can contain vec lits in-line" in {
@@ -506,21 +506,21 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
_.foo -> Vec(3, UInt(4.W)).Lit(0 -> 0xa.U, 1 -> 0xb.U, 2 -> 0xc.U),
_.bar -> Vec(2, UInt(4.W)).Lit(0 -> 0xd.U, 1 -> 0xe.U)
)
- bundle.litValue().toString(16) should be("cbaed")
+ bundle.litValue.toString(16) should be("cbaed")
}
"Vec.Lit is a trivial Vec literal factory" in {
val vec = Vec.Lit(0xa.U, 0xb.U)
- vec(0).litValue() should be(0xa)
- vec(1).litValue() should be(0xb)
+ vec(0).litValue should be(0xa)
+ vec(1).litValue should be(0xb)
}
"Vec.Lit bases it's element width on the widest literal supplied" in {
val vec = Vec.Lit(0xa.U, 0xbbbb.U)
- vec(0).litValue() should be(0xa)
- vec(1).litValue() should be(0xbbbb)
+ vec(0).litValue should be(0xa)
+ vec(1).litValue should be(0xbbbb)
vec.length should be(2)
vec.getWidth should be(16 * 2)
- vec.litValue() should be(BigInt("bbbb000a", 16))
+ vec.litValue should be(BigInt("bbbb000a", 16))
}
}
diff --git a/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala b/src/test/scala/chiselTests/VerificationSpec.scala
index 1e080739..2d7144df 100644
--- a/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala
+++ b/src/test/scala/chiselTests/VerificationSpec.scala
@@ -1,15 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
-package chiselTests.experimental.verification
+package chiselTests
import chisel3._
import chisel3.experimental.{ChiselAnnotation, verification => formal}
import chisel3.stage.ChiselStage
-import chiselTests.ChiselPropSpec
import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation}
+import org.scalatest.matchers.should.Matchers
import java.io.File
-import org.scalatest.matchers.should.Matchers
class SimpleTest extends Module {
val io = IO(new Bundle{
@@ -17,10 +16,10 @@ class SimpleTest extends Module {
val out = Output(UInt(8.W))
})
io.out := io.in
- formal.cover(io.in === 3.U)
+ cover(io.in === 3.U)
when (io.in === 3.U) {
- formal.assume(io.in =/= 2.U)
- formal.assert(io.out === io.in)
+ assume(io.in =/= 2.U)
+ assert(io.out === io.in)
}
}
@@ -35,7 +34,7 @@ object VerifAnnotation {
/** Create annotation for a given verification component.
* @param c component to be annotated
*/
- def annotate(c: experimental.BaseSim): Unit = {
+ def annotate(c: VerificationStatement): Unit = {
chisel3.experimental.annotate(new ChiselAnnotation {
def toFirrtl: VerifAnnotation = VerifAnnotation(c.toTarget)
})
@@ -60,8 +59,8 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
assertContains(lines, "when _T_6 : @[VerificationSpec.scala")
assertContains(lines, "assume(clock, _T_4, UInt<1>(\"h1\"), \"\")")
- assertContains(lines, "when _T_9 : @[VerificationSpec.scala")
- assertContains(lines, "assert(clock, _T_7, UInt<1>(\"h1\"), \"\")")
+ assertContains(lines, "when _T_10 : @[VerificationSpec.scala")
+ assertContains(lines, "assert(clock, _T_8, UInt<1>(\"h1\"), \"\")")
}
property("annotation of verification constructs should work") {
@@ -72,9 +71,9 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val out = Output(UInt(8.W))
})
io.out := io.in
- val cov = formal.cover(io.in === 3.U)
- val assm = formal.assume(io.in =/= 2.U)
- val asst = formal.assert(io.out === io.in)
+ val cov = cover(io.in === 3.U)
+ val assm = chisel3.assume(io.in =/= 2.U)
+ val asst = chisel3.assert(io.out === io.in)
VerifAnnotation.annotate(cov)
VerifAnnotation.annotate(assm)
VerifAnnotation.annotate(asst)
@@ -93,7 +92,7 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val annoLines = scala.io.Source.fromFile(annoFile).getLines.toList
// check for expected verification annotations
- exactly(3, annoLines) should include ("chiselTests.experimental.verification.VerifAnnotation")
+ exactly(3, annoLines) should include ("chiselTests.VerifAnnotation")
exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>asst")
exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>assm")
exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>cov")
@@ -106,7 +105,7 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
// check that verification components have expected names
exactly(1, firLines) should include ("cover(clock, _T, UInt<1>(\"h1\"), \"\") : cov")
exactly(1, firLines) should include ("assume(clock, _T_3, UInt<1>(\"h1\"), \"\") : assm")
- exactly(1, firLines) should include ("assert(clock, _T_6, UInt<1>(\"h1\"), \"\") : asst")
+ exactly(1, firLines) should include ("assert(clock, _T_7, UInt<1>(\"h1\"), \"\") : asst")
}
property("annotation of verification constructs with suggested name should work") {
@@ -118,11 +117,11 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
})
io.out := io.in
- val goodbye = formal.assert(io.in === 1.U)
+ val goodbye = chisel3.assert(io.in === 1.U)
goodbye.suggestName("hello")
VerifAnnotation.annotate(goodbye)
- VerifAnnotation.annotate(formal.assume(io.in =/= 2.U).suggestName("howdy"))
+ VerifAnnotation.annotate(chisel3.assume(io.in =/= 2.U).suggestName("howdy"))
}
// compile circuit
@@ -138,7 +137,7 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val annoLines = scala.io.Source.fromFile(annoFile).getLines.toList
// check for expected verification annotations
- exactly(2, annoLines) should include ("chiselTests.experimental.verification.VerifAnnotation")
+ exactly(2, annoLines) should include ("chiselTests.VerifAnnotation")
exactly(1, annoLines) should include ("~AnnotationRenameTest|AnnotationRenameTest>hello")
exactly(1, annoLines) should include ("~AnnotationRenameTest|AnnotationRenameTest>howdy")
@@ -149,6 +148,6 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
// check that verification components have expected names
exactly(1, firLines) should include ("assert(clock, _T, UInt<1>(\"h1\"), \"\") : hello")
- exactly(1, firLines) should include ("assume(clock, _T_3, UInt<1>(\"h1\"), \"\") : howdy")
+ exactly(1, firLines) should include ("assume(clock, _T_4, UInt<1>(\"h1\"), \"\") : howdy")
}
}
diff --git a/src/test/scala/chiselTests/aop/SelectSpec.scala b/src/test/scala/chiselTests/aop/SelectSpec.scala
index e09e78c8..2b47c6b8 100644
--- a/src/test/scala/chiselTests/aop/SelectSpec.scala
+++ b/src/test/scala/chiselTests/aop/SelectSpec.scala
@@ -133,11 +133,10 @@ class SelectSpec extends ChiselFlatSpec {
{ dut: SelectTester =>
Seq(Select.Stop(
Seq(
- When(Select.ops("eq")(dut).dropRight(1).last.asInstanceOf[Bool]),
- When(dut.nreset),
- WhenNot(dut.overflow)
+ When(Select.ops("eq")(dut)(1).asInstanceOf[Bool]),
+ When(dut.overflow)
),
- 1,
+ 0,
dut.clock
))
}
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala
index d1620e88..7c5d170b 100644
--- a/src/test/scala/chiselTests/experimental/DataView.scala
+++ b/src/test/scala/chiselTests/experimental/DataView.scala
@@ -5,7 +5,9 @@ package chiselTests.experimental
import chiselTests.ChiselFlatSpec
import chisel3._
import chisel3.experimental.dataview._
+import chisel3.experimental.conversions._
import chisel3.experimental.DataMirror.internal.chiselTypeClone
+import chisel3.experimental.HWTuple2
import chisel3.stage.ChiselStage
import chisel3.util.{Decoupled, DecoupledIO}
@@ -50,69 +52,6 @@ object FlatDecoupledDataView {
implicit val view2 = view.invert(_ => new FlatDecoupled)
}
-// This should become part of Chisel in a later PR
-object Tuple2DataProduct {
- implicit def tuple2DataProduct[A : DataProduct, B : DataProduct] = new DataProduct[(A, B)] {
- def dataIterator(tup: (A, B), path: String): Iterator[(Data, String)] = {
- val dpa = implicitly[DataProduct[A]]
- val dpb = implicitly[DataProduct[B]]
- val (a, b) = tup
- dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2")
- }
- }
-}
-
-// This should become part of Chisel in a later PR
-object HWTuple {
- import Tuple2DataProduct._
-
- class HWTuple2[A <: Data, B <: Data](val _1: A, val _2: B) extends Bundle
-
- implicit def view[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data](
- implicit v1: DataView[T1, V1], v2: DataView[T2, V2]
- ): DataView[(T1, T2), HWTuple2[V1, V2]] =
- DataView.mapping(
- { case (a, b) => new HWTuple2(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType)},
- { case ((a, b), hwt) =>
- Seq(a.viewAs[V1] -> hwt._1,
- b.viewAs[V2] -> hwt._2)
- }
- )
-
- implicit def tuple2hwtuple[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data](
- tup: (T1, T2))(implicit v1: DataView[T1, V1], v2: DataView[T2, V2]
- ): HWTuple2[V1, V2] = tup.viewAs[HWTuple2[V1, V2]]
-}
-
-// This should become part of Chisel in a later PR
-object SeqDataProduct {
- // Should we special case Seq[Data]?
- implicit def seqDataProduct[A : DataProduct]: DataProduct[Seq[A]] = new DataProduct[Seq[A]] {
- def dataIterator(a: Seq[A], path: String): Iterator[(Data, String)] = {
- val dpa = implicitly[DataProduct[A]]
- a.iterator
- .zipWithIndex
- .flatMap { case (elt, idx) =>
- dpa.dataIterator(elt, s"$path[$idx]")
- }
- }
- }
-}
-
-object SeqToVec {
- import SeqDataProduct._
-
- // TODO this would need a better way to determine the prototype for the Vec
- implicit def seqVec[A : DataProduct, B <: Data](implicit dv: DataView[A, B]): DataView[Seq[A], Vec[B]] =
- DataView.mapping[Seq[A], Vec[B]](
- xs => Vec(xs.size, chiselTypeClone(xs.head.viewAs[B])), // xs.head is not correct in general
- { case (s, v) => s.zip(v).map { case (a, b) => a.viewAs[B] -> b } }
- )
-
- implicit def seq2Vec[A : DataProduct, B <: Data](xs: Seq[A])(implicit dv: DataView[A, B]): Vec[B] =
- xs.viewAs[Vec[B]]
-}
-
class DataViewSpec extends ChiselFlatSpec {
behavior of "DataView"
@@ -327,15 +266,14 @@ class DataViewSpec extends ChiselFlatSpec {
chirrtl should include ("z.fizz <= b.foo")
}
- // This example should be turned into a built-in feature
- it should "enable implementing \"HardwareTuple\"" in {
- import HWTuple._
-
+ it should "enable using Seq like Data" in {
class MyModule extends Module {
val a, b, c, d = IO(Input(UInt(8.W)))
val sel = IO(Input(Bool()))
val y, z = IO(Output(UInt(8.W)))
- (y, z) := Mux(sel, (a, b), (c, d))
+ // Unclear why the implicit conversion does not work in this case for Seq
+ // That being said, it's easy enough to cast via `.viewAs` with or without
+ Seq(y, z) := Mux(sel, Seq(a, b).viewAs, Seq(c, d).viewAs[Vec[UInt]])
}
// Verilog instead of CHIRRTL because the optimizations make it much prettier
val verilog = ChiselStage.emitVerilog(new MyModule)
@@ -343,25 +281,8 @@ class DataViewSpec extends ChiselFlatSpec {
verilog should include ("assign z = sel ? b : d;")
}
- it should "support nesting of tuples" in {
- import Tuple2DataProduct._
- import HWTuple._
-
- class MyModule extends Module {
- val a, b, c, d = IO(Input(UInt(8.W)))
- val w, x, y, z = IO(Output(UInt(8.W)))
- ((w, x), (y, z)) := ((a, b), (c, d))
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include ("w <= a")
- chirrtl should include ("x <= b")
- chirrtl should include ("y <= c")
- chirrtl should include ("z <= d")
- }
-
// This example should be turned into a built-in feature
it should "enable viewing Seqs as Vecs" in {
- import SeqToVec._
class MyModule extends Module {
val a, b, c = IO(Input(UInt(8.W)))
@@ -376,11 +297,6 @@ class DataViewSpec extends ChiselFlatSpec {
}
it should "support recursive composition of views" in {
- import Tuple2DataProduct._
- import SeqDataProduct._
- import SeqToVec._
- import HWTuple._
-
class MyModule extends Module {
val a, b, c, d = IO(Input(UInt(8.W)))
val w, x, y, z = IO(Output(UInt(8.W)))
@@ -397,12 +313,26 @@ class DataViewSpec extends ChiselFlatSpec {
verilog should include ("assign z = d;")
}
- it should "error if you try to dynamically index a Vec view" in {
- import SeqDataProduct._
- import SeqToVec._
- import Tuple2DataProduct._
- import HWTuple._
+ it should "support dynamic indexing for Vec identity views" in {
+ class MyModule extends Module {
+ val dataIn = IO(Input(UInt(8.W)))
+ val addr = IO(Input(UInt(2.W)))
+ val dataOut = IO(Output(UInt(8.W)))
+
+ val vec = RegInit(0.U.asTypeOf(Vec(4, UInt(8.W))))
+ val view = vec.viewAs[Vec[UInt]]
+ // Dynamic indexing is more of a "generator" in Chisel3 than an individual node
+ // This style is not recommended, this is just testing the behavior
+ val selected = view(addr)
+ selected := dataIn
+ dataOut := selected
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ chirrtl should include ("vec[addr] <= dataIn")
+ chirrtl should include ("dataOut <= vec[addr]")
+ }
+ it should "error if you try to dynamically index a Vec view that does not correspond to a Vec target" in {
class MyModule extends Module {
val inA, inB = IO(Input(UInt(8.W)))
val outA, outB = IO(Output(UInt(8.W)))
@@ -411,6 +341,7 @@ class DataViewSpec extends ChiselFlatSpec {
val a, b, c, d = RegInit(0.U)
// Dynamic indexing is more of a "generator" in Chisel3 than an individual node
+ // This style is not recommended, this is just testing the behavior
val selected = Seq((a, b), (c, d)).apply(idx)
selected := (inA, inB)
(outA, outB) := selected
@@ -434,7 +365,6 @@ class DataViewSpec extends ChiselFlatSpec {
}
it should "error if the mapping is non-total in the target" in {
- import Tuple2DataProduct._
implicit val dv = DataView[(UInt, UInt), UInt](_ => UInt(), _._1 -> _)
class MyModule extends Module {
val a, b = IO(Input(UInt(8.W)))
@@ -533,7 +463,6 @@ class DataViewSpec extends ChiselFlatSpec {
}
it should "NOT error if the mapping is non-total in the target" in {
- import Tuple2DataProduct._
implicit val dv = PartialDataView[(UInt, UInt), UInt](_ => UInt(), _._2 -> _)
class MyModule extends Module {
val a, b = IO(Input(UInt(8.W)))
diff --git a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala
index 92091631..a17b0f40 100644
--- a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala
+++ b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala
@@ -4,8 +4,8 @@ package chiselTests.experimental
import chisel3._
import chisel3.experimental.dataview._
+import chisel3.experimental.conversions._
import chisel3.experimental.{ChiselAnnotation, annotate}
-import chisel3.stage.ChiselStage
import chiselTests.ChiselFlatSpec
object DataViewTargetSpec {
@@ -127,7 +127,6 @@ class DataViewTargetSpec extends ChiselFlatSpec {
}
it should "support annotating views that cannot be mapped to a single ReferenceTarget" in {
- import HWTuple._
class MyBundle extends Bundle {
val a, b = Input(UInt(8.W))
val c, d = Output(UInt(8.W))
diff --git a/src/test/scala/chiselTests/experimental/TraceSpec.scala b/src/test/scala/chiselTests/experimental/TraceSpec.scala
new file mode 100644
index 00000000..59548921
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/TraceSpec.scala
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests
+
+import chisel3._
+import chisel3.experimental.ChiselEnum
+import chisel3.experimental.Trace._
+import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage, DesignAnnotation}
+import chisel3.util.experimental.InlineInstance
+import firrtl.AnnotationSeq
+import firrtl.annotations.TargetToken.{Instance, OfModule, Ref}
+import firrtl.annotations.{CompleteTarget, InstanceTarget, ReferenceTarget}
+import org.scalatest.matchers.should.Matchers
+
+class TraceSpec extends ChiselFlatSpec with Matchers {
+
+ def refTarget(topName: String, ref: String, path: Seq[(Instance, OfModule)] = Seq()) =
+ ReferenceTarget(topName, topName, path, ref, Seq())
+
+ def instTarget(topName: String, instance: String, ofModule: String, path: Seq[(Instance, OfModule)] = Seq()) =
+ InstanceTarget(topName, topName, path, instance, ofModule)
+
+ def compile(testName: String, gen: () => Module): (os.Path, AnnotationSeq) = {
+ val testDir = os.Path(createTestDirectory(testName).getAbsolutePath)
+ val annos = (new ChiselStage).execute(
+ Array("--target-dir", s"$testDir"),
+ Seq(
+ ChiselGeneratorAnnotation(gen)
+ )
+ )
+ (testDir, annos)
+ }
+
+ "TraceFromAnnotations" should "be able to get nested name." in {
+ class Bundle0 extends Bundle {
+ val a = UInt(8.W)
+ val b = Bool()
+ val c = Enum0.Type
+ }
+
+ class Bundle1 extends Bundle {
+ val a = new Bundle0
+ val b = Vec(4, Vec(4, Bool()))
+ }
+
+ class Module0 extends Module {
+ val i = IO(Input(new Bundle1))
+ val o = IO(Output(new Bundle1))
+ val r = Reg(new Bundle1)
+ o := r
+ r := i
+
+ traceName(r)
+ traceName(i)
+ traceName(o)
+ }
+
+ class Module1 extends Module {
+ val i = IO(Input(new Bundle1))
+ val m0 = Module(new Module0)
+ m0.i := i
+ m0.o := DontCare
+ }
+
+ object Enum0 extends ChiselEnum {
+ val s0, s1, s2 = Value
+ }
+
+ val (testDir, annos) = compile("TraceFromAnnotaions", () => new Module1)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Module1]
+ // out of Builder.
+
+ val oneTarget = finalTarget(annos)(dut.m0.r.a.a).head
+ val ioTarget = finalTarget(annos)(dut.m0.i.b(1)(2)).head
+
+ val topName = "Module1"
+ oneTarget should be(refTarget(topName, "r_a_a", Seq(Instance("m0") -> OfModule("Module0"))))
+
+ ioTarget should be(refTarget(topName, "i_b_1_2", Seq(Instance("m0") -> OfModule("Module0"))))
+
+ // Below codes doesn't needs to be a FIRRTL Transform.
+ def generateVerilatorConfigFile(data: Seq[Data], annos: AnnotationSeq): String =
+ """`verilator_config
+ |lint_off -rule unused
+ |lint_off -rule declfilename
+ |""".stripMargin +
+ data
+ .flatMap(finalTarget(annos))
+ .toSet
+ .map { target: CompleteTarget =>
+ s"""public_flat_rd -module "${target.tokens.collectFirst { case OfModule(m) => m }.get}" -var "${target.tokens.collectFirst { case Ref(r) => r }.get}""""
+ }
+ .mkString("\n") + "\n"
+
+ def verilatorTemplate(data: Seq[Data], annos: AnnotationSeq): String = {
+ val vpiNames = data.flatMap(finalTarget(annos)).map { ct =>
+ s"""TOP.${ct.circuit}.${ct.path.map { case (Instance(i), _) => i }.mkString(".")}.${ct.tokens.collectFirst { case Ref(r) => r }.get}"""
+ }
+ s"""
+ |#include "V${topName}.h"
+ |#include "verilated_vpi.h"
+ |#include <memory>
+ |#include <verilated.h>
+ |
+ |int vpiGetInt(const char name[]) {
+ | vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8 *)name, NULL);
+ | if (!vh1)
+ | vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found");
+ | s_vpi_value v;
+ | v.format = vpiIntVal;
+ | vpi_get_value(vh1, &v);
+ | return v.value.integer;
+ |}
+ |
+ |int main(int argc, char **argv) {
+ | const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
+ | contextp->commandArgs(argc, argv);
+ | const std::unique_ptr<V$topName> top{new V$topName{contextp.get(), "TOP"}};
+ | top->reset = 0;
+ | top->clock = 0;
+ | int a_b = 1;
+ | top->i_a_b = a_b;
+ | bool started = false;
+ | int ticks = 20;
+ | while (ticks--) {
+ | contextp->timeInc(1);
+ | top->clock = !top->clock;
+ | if (!top->clock) {
+ | if (contextp->time() > 1 && contextp->time() < 10) {
+ | top->reset = 1;
+ | } else {
+ | top->reset = 0;
+ | started = true;
+ | }
+ | a_b = a_b ? 0 : 1;
+ | top->i_a_b = a_b;
+ | }
+ | top->eval();
+ | VerilatedVpi::callValueCbs();
+ | if (started && !top->clock) {
+ | const int i = top->i_a_b;
+ | const int o = vpiGetInt("${vpiNames.head}");
+ | if (i == o)
+ | vl_fatal(__FILE__, __LINE__, "sim_main", "${vpiNames.head} should be the old value of Module1.i_a_b");
+ | printf("${vpiNames.head}=%d Module1.m0.o_a_b=%d\\n", i, o);
+ | }
+ | }
+ | top->final();
+ | return 0;
+ |}
+ |""".stripMargin
+ }
+
+ val config = os.temp(dir = testDir, contents = generateVerilatorConfigFile(Seq(dut.m0.o.a.b), annos))
+ val verilog = testDir / s"$topName.v"
+ val cpp = os.temp(dir = testDir, suffix = ".cpp", contents = verilatorTemplate(Seq(dut.m0.o.a.b), annos))
+ val exe = testDir / "obj_dir" / s"V$topName"
+ os.proc("verilator", "-Wall", "--cc", "--exe", "--build", "--vpi", s"$cpp", s"$verilog", s"$config").call(stdout = os.Inherit, stderr = os.Inherit, cwd = testDir)
+ assert(os.proc(s"$exe").call(stdout = os.Inherit, stderr = os.Inherit).exitCode == 0, "verilator should exit peacefully")
+ }
+
+ "TraceFromCollideBundle" should "work" in {
+ class CollideModule extends Module {
+ val a = IO(Input(Vec(2, new Bundle {
+ val b = Flipped(Bool())
+ val c = Vec(2, new Bundle {
+ val d = UInt(2.W)
+ val e = Flipped(UInt(3.W))
+ })
+ val c_1_e = UInt(4.W)
+ })))
+ val a_0_c = IO(Output(UInt(5.W)))
+ val a__0 = IO(Output(UInt(5.W)))
+ a_0_c := DontCare
+ a__0 := DontCare
+
+ traceName(a)
+ traceName(a_0_c)
+ traceName(a__0)
+ }
+
+ val (_, annos) = compile("TraceFromCollideBundle", () => new CollideModule)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[CollideModule]
+
+ val topName = "CollideModule"
+
+ val a0 = finalTarget(annos)(dut.a(0))
+ val a__0 = finalTarget(annos)(dut.a__0).head
+ val a__0_ref = refTarget(topName, "a__0")
+ a0.foreach(_ shouldNot be(a__0_ref))
+ a__0 should be(a__0_ref)
+
+ val a0_c = finalTarget(annos)(dut.a(0).c)
+ val a_0_c = finalTarget(annos)(dut.a_0_c).head
+ val a_0_c_ref = refTarget(topName, "a_0_c")
+ a0_c.foreach(_ shouldNot be(a_0_c_ref))
+ a_0_c should be(a_0_c_ref)
+
+ val a0_c1_e = finalTarget(annos)(dut.a(0).c(1).e).head
+ val a0_c_1_e = finalTarget(annos)(dut.a(0).c_1_e).head
+ a0_c1_e should be(refTarget(topName, "a_0_c__1_e"))
+ a0_c_1_e should be(refTarget(topName, "a_0_c_1_e"))
+ }
+
+ "Inline should work" should "work" in {
+ class Module0 extends Module {
+ val i = IO(Input(Bool()))
+ val o = IO(Output(Bool()))
+ traceName(i)
+ o := !i
+ }
+
+ class Module1 extends Module {
+ val i = IO(Input(Bool()))
+ val o = IO(Output(Bool()))
+ val m0 = Module(new Module0 with InlineInstance)
+ m0.i := i
+ o := m0.o
+ }
+
+ val (_, annos) = compile("Inline", () => new Module1)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Module1]
+
+ val m0_i = finalTarget(annos)(dut.m0.i).head
+ m0_i should be(refTarget("Module1", "m0_i"))
+ }
+
+ "Constant Propagation" should "be turned off by traceName" in {
+ class Module0 extends Module {
+ val i = WireDefault(1.U)
+ val i0 = i + 1.U
+ val o = IO(Output(UInt(2.W)))
+ traceName(i0)
+ o := i0
+ }
+
+ val (_, annos) = compile("ConstantProp", () => new Module0)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Module0]
+
+ val i0 = finalTarget(annos)(dut.i0).head
+ i0 should be(refTarget("Module0", "i0"))
+ }
+
+ "Nested Module" should "work" in {
+ class Io extends Bundle {
+ val i = Input(Bool())
+ val o = Output(Bool())
+ }
+
+ class Not extends Module {
+ val io = IO(new Io)
+ io.o := !io.i
+ }
+
+ class M1 extends Module {
+ val io = IO(new Io)
+ val not = Module(new Not)
+ not.io <> io
+ }
+
+ class M2 extends Module {
+ val io = IO(new Io)
+ val m1 = Module(new M1 with InlineInstance)
+ val not = Module(new Not)
+
+ m1.io.i := io.i
+ not.io.i := io.i
+
+ io.o := m1.io.o && not.io.o
+ }
+
+ class M3 extends Module {
+ val io = IO(new Io)
+ val m2 = Module(new M2)
+ io <> m2.io
+ traceName(m2.not)
+ traceName(m2.m1.not)
+ }
+
+ val (_, annos) = compile("NestedModule", () => new M3)
+ val m3 = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[M3]
+
+ val m2_m1_not = finalTarget(annos)(m3.m2.m1.not).head
+ val m2_not = finalTarget(annos)(m3.m2.not).head
+
+ m2_m1_not should be(instTarget("M3", "m1_not", "Not", Seq(Instance("m2") -> OfModule("M2"))))
+ m2_not should be(instTarget("M3", "not", "Not", Seq(Instance("m2") -> OfModule("M2"))))
+ }
+
+ "All traced signal" should "generate" in {
+ class M extends Module {
+ val a = Wire(Bool())
+ val b = Wire(Vec(2, Bool()))
+ a := DontCare
+ b := DontCare
+ Seq(a, b).foreach(traceName)
+ }
+ val (_, annos) = compile("NestedModule", () => new M)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[M]
+ val allTargets = finalTargetMap(annos)
+ allTargets(dut.a.toAbsoluteTarget) should be (Seq(refTarget("M", "a")))
+ allTargets(dut.b.toAbsoluteTarget) should be (Seq(
+ refTarget("M", "b_0"),
+ refTarget("M", "b_1"),
+ ))
+ allTargets(dut.b(0).toAbsoluteTarget) should be (Seq(refTarget("M", "b_0")))
+ allTargets(dut.b(1).toAbsoluteTarget) should be (Seq(refTarget("M", "b_1")))
+ }
+}
diff --git a/src/test/scala/chiselTests/experimental/Tuple.scala b/src/test/scala/chiselTests/experimental/Tuple.scala
new file mode 100644
index 00000000..5f897fbc
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/Tuple.scala
@@ -0,0 +1,163 @@
+// See LICENSE for license details.
+
+package chiselTests.experimental
+
+import chiselTests.ChiselFlatSpec
+import chisel3._
+import chisel3.experimental.conversions._
+import chisel3.stage.ChiselStage
+
+class TupleSpec extends ChiselFlatSpec {
+
+ behavior of "Tuple"
+
+ it should "enable using Tuple2 like Data" in {
+ class MyModule extends Module {
+ val a, b, c, d = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val y, z = IO(Output(UInt(8.W)))
+ (y, z) := Mux(sel, (a, b), (c, d))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("assign y = sel ? a : c;")
+ verilog should include ("assign z = sel ? b : d;")
+ }
+
+ it should "support nesting of tuples" in {
+ class MyModule extends Module {
+ val a, b, c, d = IO(Input(UInt(8.W)))
+ val w, x, y, z = IO(Output(UInt(8.W)))
+ ((w, x), (y, z)) := ((a, b), (c, d))
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ chirrtl should include ("w <= a")
+ chirrtl should include ("x <= b")
+ chirrtl should include ("y <= c")
+ chirrtl should include ("z <= d")
+ }
+
+ it should "enable using Tuple3 like Data" in {
+ class MyModule extends Module {
+ val a, b, c = IO(Input(UInt(8.W)))
+ val f, g, h = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val v, w, x = IO(Output(UInt(8.W)))
+ (v, w, x) := Mux(sel, (a, b, c), (f, g, h))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("assign v = sel ? a : f;")
+ verilog should include ("assign w = sel ? b : g;")
+ verilog should include ("assign x = sel ? c : h;")
+ }
+
+ it should "enable using Tuple4 like Data" in {
+ class MyModule extends Module {
+ val a, b, c, d = IO(Input(UInt(8.W)))
+ val f, g, h, i = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val v, w, x, y = IO(Output(UInt(8.W)))
+ (v, w, x, y) := Mux(sel, (a, b, c, d), (f, g, h, i))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("assign v = sel ? a : f;")
+ verilog should include ("assign w = sel ? b : g;")
+ verilog should include ("assign x = sel ? c : h;")
+ verilog should include ("assign y = sel ? d : i;")
+ }
+
+ it should "enable using Tuple5 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4) := Mux(sel, (a0, a1, a2, a3, a4), (b0, b1, b2, b3, b4))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 5) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple6 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5) := Mux(sel, (a0, a1, a2, a3, a4, a5), (b0, b1, b2, b3, b4, b5))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 6) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple7 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5, a6 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5, b6 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5, z6 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5, z6) := Mux(sel, (a0, a1, a2, a3, a4, a5, a6), (b0, b1, b2, b3, b4, b5, b6))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 7) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple8 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5, a6, a7 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5, b6, b7 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5, z6, z7 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5, z6, z7) := Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7), (b0, b1, b2, b3, b4, b5, b6, b7))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 8) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple9 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5, a6, a7, a8 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5, b6, b7, b8 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5, z6, z7, z8 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5, z6, z7, z8) :=
+ Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7, a8), (b0, b1, b2, b3, b4, b5, b6, b7, b8))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 9) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple10 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5, z6, z7, z8, z9 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5, z6, z7, z8, z9) :=
+ Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), (b0, b1, b2, b3, b4, b5, b6, b7, b8, b9))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 10) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+}
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala b/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala
index 43111fdd..eba412f1 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala
@@ -5,24 +5,20 @@ package chiselTests.experimental.hierarchy
import _root_.firrtl.annotations._
import chisel3.experimental.{annotate, BaseModule}
import chisel3.Data
-import chisel3.experimental.hierarchy.{Instance, Definition}
+import chisel3.experimental.hierarchy.{Instance, Definition, Hierarchy}
object Annotations {
case class MarkAnnotation(target: IsMember, tag: String) extends SingleTargetAnnotation[IsMember] {
def duplicate(n: IsMember): Annotation = this.copy(target = n)
}
- case class MarkChiselInstanceAnnotation[B <: BaseModule](d: Instance[B], tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation {
- def toFirrtl = MarkAnnotation(d.toTarget, tag)
- }
- case class MarkChiselDefinitionAnnotation[B <: BaseModule](d: Definition[B], tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation {
+ case class MarkChiselHierarchyAnnotation[B <: BaseModule](d: Hierarchy[B], tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation {
def toFirrtl = MarkAnnotation(d.toTarget, tag)
}
case class MarkChiselAnnotation(d: Data, tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation {
def toFirrtl = if(isAbsolute) MarkAnnotation(d.toAbsoluteTarget, tag) else MarkAnnotation(d.toTarget, tag)
}
def mark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, false))
- def mark[B <: BaseModule](d: Instance[B], tag: String): Unit = annotate(MarkChiselInstanceAnnotation(d, tag, false))
- def mark[B <: BaseModule](d: Definition[B], tag: String): Unit = annotate(MarkChiselDefinitionAnnotation(d, tag, false))
+ def mark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true))
def amark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, true))
- def amark[B <: BaseModule](d: Instance[B], tag: String): Unit = annotate(MarkChiselInstanceAnnotation(d, tag, true))
+ def amark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true))
}
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala
index 19261c36..f33f7869 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala
@@ -40,6 +40,44 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
val (chirrtl, _) = getFirrtlAndAnnos(new Top)
chirrtl.serialize should include ("inst i0 of HasUninferredReset")
}
+ it("0.3: module names of repeated definition should be sequential") {
+ class Top extends Module {
+ val k = Module(new AddTwoParameterized(4, (x: Int) => Seq.tabulate(x){j =>
+ val addOneDef = Definition(new AddOneParameterized(x+j))
+ val addOne = Instance(addOneDef)
+ addOne
+ }))
+ }
+ val (chirrtl, _) = getFirrtlAndAnnos(new Top)
+ chirrtl.serialize should include ("module AddOneParameterized :")
+ chirrtl.serialize should include ("module AddOneParameterized_1 :")
+ chirrtl.serialize should include ("module AddOneParameterized_2 :")
+ chirrtl.serialize should include ("module AddOneParameterized_3 :")
+ }
+ it("0.4: multiple instantiations should have sequential names") {
+ class Top extends Module {
+ val addOneDef = Definition(new AddOneParameterized(4))
+ val addOne = Instance(addOneDef)
+ val otherAddOne = Module(new AddOneParameterized(4))
+ }
+ val (chirrtl, _) = getFirrtlAndAnnos(new Top)
+ chirrtl.serialize should include ("module AddOneParameterized :")
+ chirrtl.serialize should include ("module AddOneParameterized_1 :")
+ }
+ it("0.5: nested definitions should have sequential names") {
+ class Top extends Module {
+ val k = Module(new AddTwoWithNested(4, (x: Int) => Seq.tabulate(x){j =>
+ val addOneDef = Definition(new AddOneWithNested(x+j))
+ val addOne = Instance(addOneDef)
+ addOne
+ }))
+ }
+ val (chirrtl, _) = getFirrtlAndAnnos(new Top)
+ chirrtl.serialize should include ("module AddOneWithNested :")
+ chirrtl.serialize should include ("module AddOneWithNested_1 :")
+ chirrtl.serialize should include ("module AddOneWithNested_2 :")
+ chirrtl.serialize should include ("module AddOneWithNested_3 :")
+ }
}
describe("1: Annotations on definitions in same chisel compilation") {
it("1.0: should work on a single definition, annotating the definition") {
@@ -97,7 +135,7 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
mark(definition.i1, "i0.i1")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_2".it, "i0.i1"))
+ annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_1".it, "i0.i1"))
}
// Can you define an instantiable container? I think not.
// Instead, we can test the instantiable container in a definition
@@ -258,6 +296,17 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
val (_, annos) = getFirrtlAndAnnos(new Top)
annos should contain(MarkAnnotation("~Top|HasPublicConstructorArgs>x".rt, "10"))
}
+ it("3.10: should work on unimplemented vals in abstract classes/traits") {
+ class Top() extends Module {
+ val i = Definition(new ConcreteHasBlah())
+ def f(d: Definition[HasBlah]): Unit = {
+ mark(d, d.blah.toString)
+ }
+ f(i)
+ }
+ val (_, annos) = getFirrtlAndAnnos(new Top)
+ annos should contain(MarkAnnotation("~Top|ConcreteHasBlah".mt, "10"))
+ }
}
describe("4: toDefinition") {
it("4.0: should work on modules") {
@@ -311,7 +360,7 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
amark(i.i1.in, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_2>in".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_1>in".rt, "blah"))
}
it("5.3: toAbsoluteTarget on a submodule's data, in an aggregate, within a definition") {
class Top() extends Module {
@@ -319,7 +368,7 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
amark(i.i1.x.head, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|InstantiatesHasVec/i1:HasVec_2>x[0]".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|InstantiatesHasVec/i1:HasVec_1>x[0]".rt, "blah"))
}
}
describe("6: @instantiable traits should work as expected") {
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
index 23b8c9c0..c0f504ff 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
@@ -36,6 +36,19 @@ object Examples {
out := innerWire
}
@instantiable
+ class AddOneParameterized(width: Int) extends Module {
+ @public val in = IO(Input(UInt(width.W)))
+ @public val out = IO(Output(UInt(width.W)))
+ out := in + 1.U
+ }
+ class AddOneWithNested(width: Int) extends Module {
+ @public val in = IO(Input(UInt(width.W)))
+ @public val out = IO(Output(UInt(width.W)))
+ val addOneDef = Seq.fill(3)(Definition(new AddOne))
+ out := in + 1.U
+ }
+
+ @instantiable
class AddTwo extends Module {
@public val in = IO(Input(UInt(32.W)))
@public val out = IO(Output(UInt(32.W)))
@@ -58,6 +71,33 @@ object Examples {
out := i1.out
}
@instantiable
+ class AddTwoParameterized(width: Int, makeParameterizedOnes: Int => Seq[Instance[AddOneParameterized]]) extends Module {
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt(width.W)))
+ val addOnes = makeParameterizedOnes(width)
+ addOnes.head.in := in
+ out := addOnes.last.out
+ addOnes.zip(addOnes.tail).foreach{ case (head, tail) => tail.in := head.out}
+ }
+ @instantiable
+ class AddTwoWithNested(width: Int, makeParameterizedOnes: Int => Seq[Instance[AddOneWithNested]]) extends Module {
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt(width.W)))
+ val addOnes = makeParameterizedOnes(width)
+ }
+
+ @instantiable
+ class AddFour extends Module {
+ @public val in = IO(Input(UInt(32.W)))
+ @public val out = IO(Output(UInt(32.W)))
+ @public val definition = Definition(new AddTwoMixedModules)
+ @public val i0 = Instance(definition)
+ @public val i1 = Instance(definition)
+ i0.in := in
+ i1.in := i0.out
+ out := i1.out
+ }
+ @instantiable
class AggregatePortModule extends Module {
@public val io = IO(new Bundle {
val in = Input(UInt(32.W))
@@ -183,4 +223,17 @@ object Examples {
@public val out = IO(Output(UInt(3.W)))
out := RegNext(in)
}
+ @instantiable
+ abstract class HasBlah() extends Module {
+ @public val blah: Int
+ }
+
+ @instantiable
+ class ConcreteHasBlah() extends HasBlah {
+ val blah = 10
+ }
+ @instantiable
+ class HasTypeParams[D <: Data](d: D) extends Module {
+ @public val blah = Wire(d)
+ }
}
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
index 3866bf87..9ceb9b40 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
@@ -89,7 +89,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
mark(i0.i1, "i0.i1")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain (MarkAnnotation("~Top|Top/i0:AddTwoMixedModules/i1:AddOne_2".it, "i0.i1"))
+ annos should contain (MarkAnnotation("~Top|Top/i0:AddTwoMixedModules/i1:AddOne_1".it, "i0.i1"))
}
it("1.5: should work on an instantiable container, annotating a wire") {
class Top extends Module {
@@ -144,6 +144,15 @@ class InstanceSpec extends ChiselFunSpec with Utils {
val (_, annos) = getFirrtlAndAnnos(new Top)
annos should contain (MarkAnnotation("~Top|AddOneWithAnnotation>innerWire".rt, "innerWire"))
}
+ it("1.11: should work on things with type parameters"){
+ class Top extends Module {
+ val definition = Definition(new HasTypeParams[UInt](UInt(3.W)))
+ val i0 = Instance(definition)
+ mark(i0.blah, "blah")
+ }
+ val (_, annos) = getFirrtlAndAnnos(new Top)
+ annos should contain (MarkAnnotation("~Top|Top/i0:HasTypeParams>blah".rt, "blah"))
+ }
}
describe("2: Annotations on designs not in the same chisel compilation") {
it("2.0: should work on an innerWire, marked in a different compilation") {
@@ -353,7 +362,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
amark(i.i1.in, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|Top/i:AddTwoMixedModules/i1:AddOne_2>in".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|Top/i:AddTwoMixedModules/i1:AddOne_1>in".rt, "blah"))
}
it("5.3: toAbsoluteTarget on a submodule's data, in an aggregate, within an instance") {
class Top() extends Module {
@@ -361,7 +370,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
amark(i.i1.x.head, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_2>x[0]".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_1>x[0]".rt, "blah"))
}
it("5.4: toAbsoluteTarget on a submodule's data, in an aggregate, within an instance, ILit") {
class MyBundle extends Bundle { val x = UInt(3.W) }
@@ -379,7 +388,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
amark(i.i1.x.head.x, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_2>x[0].x".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_1>x[0].x".rt, "blah"))
}
it("5.5: toAbsoluteTarget on a subinstance") {
class Top() extends Module {
@@ -620,7 +629,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
}
it("7.3: should work with DataView + implicit conversion") {
- import chiselTests.experimental.SeqToVec._
+ import chisel3.experimental.conversions._
@instantiable
class MyModule extends RawModule {
private val a = IO(Input(UInt(8.W)))
@@ -705,5 +714,142 @@ class InstanceSpec extends ChiselFunSpec with Utils {
}
}
}
+ describe("9: isA[..]") {
+ it("9.0: it should work on simple classes") {
+ class Top extends Module {
+ val d = Definition(new AddOne)
+ require(d.isA[AddOne])
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ it("9.1: it should not work on inner classes") {
+ class InnerClass extends Module
+ class Top extends Module {
+ val d = Definition(new InnerClass)
+ "require(d.isA[Module])" should compile // ensures that the test below is checking something useful
+ "require(d.isA[InnerClass])" shouldNot compile
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ it("9.2: it should work on super classes") {
+ class InnerClass extends Module
+ class Top extends Module {
+ val d = Definition(new InnerClass)
+ require(d.isA[Module])
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ it("9.2: it should work after casts") {
+ class Top extends Module {
+ val d0: Definition[Module] = Definition(new AddOne)
+ require(d0.isA[AddOne])
+ val d1: Definition[Module] = Definition((new AddOne).asInstanceOf[Module])
+ require(d1.isA[AddOne])
+ val i0: Instance[Module] = Instance(d0)
+ require(i0.isA[AddOne])
+ val i1: Instance[Module] = Instance(d1)
+ require(i1.isA[AddOne])
+ val i2: Instance[Module] = Instance(Definition(new AddOne))
+ require(i2.isA[AddOne])
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ }
+ describe("10: Select APIs") {
+ it("10.0: instancesOf") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules =>
+ val targets = aop.Select.instancesOf[AddOne](m.toDefinition).map { i: Instance[AddOne] => i.toTarget }
+ targets should be (Seq(
+ "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it,
+ "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".it,
+ ))
+ })
+ getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect))
+ }
+ it("10.1: instancesIn") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules =>
+ val insts = aop.Select.instancesIn(m.toDefinition)
+ val abs = insts.map { i: Instance[BaseModule] => i.toAbsoluteTarget }
+ val rel = insts.map { i: Instance[BaseModule] => i.toTarget }
+ abs should be (Seq(
+ "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it,
+ "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".it,
+ ))
+ rel should be (Seq(
+ "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it,
+ "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".it,
+ ))
+ })
+ getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect))
+ }
+ it("10.2: allInstancesOf") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ val insts = aop.Select.allInstancesOf[AddOne](m.toDefinition)
+ val abs = insts.map { i: Instance[AddOne] => i.in.toAbsoluteTarget }
+ val rel = insts.map { i: Instance[AddOne] => i.in.toTarget }
+ rel should be (Seq(
+ "~AddFour|AddFour/i0:AddTwoMixedModules/i0:AddOne>in".rt,
+ "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_1>in".rt,
+ "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>in".rt,
+ "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_1>in".rt,
+ ))
+ abs should be (Seq(
+ "~AddFour|AddFour/i0:AddTwoMixedModules/i0:AddOne>in".rt,
+ "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_1>in".rt,
+ "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>in".rt,
+ "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_1>in".rt,
+ ))
+ })
+ getFirrtlAndAnnos(new AddFour, Seq(aspect))
+ }
+ it("10.3: definitionsOf") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules =>
+ val targets = aop.Select.definitionsOf[AddOne](m.toDefinition).map { i: Definition[AddOne] => i.in.toTarget }
+ targets should be (Seq(
+ "~AddTwoMixedModules|AddOne>in".rt,
+ "~AddTwoMixedModules|AddOne_1>in".rt,
+ ))
+ })
+ getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect))
+ }
+ it("10.4: definitionsIn") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules =>
+ val targets = aop.Select.definitionsIn(m.toDefinition).map { i: Definition[BaseModule] => i.toTarget }
+ targets should be (Seq(
+ "~AddTwoMixedModules|AddOne".mt,
+ "~AddTwoMixedModules|AddOne_1".mt,
+ ))
+ })
+ getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect))
+ }
+ it("10.5: allDefinitionsOf") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ val targets = aop.Select.allDefinitionsOf[AddOne](m.toDefinition).map { i: Definition[AddOne] => i.in.toTarget }
+ targets should be (Seq(
+ "~AddFour|AddOne>in".rt,
+ "~AddFour|AddOne_1>in".rt,
+ ))
+ })
+ getFirrtlAndAnnos(new AddFour, Seq(aspect))
+ }
+ it("10.6: Select.collectDeep should fail when combined with hierarchy package") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ aop.Select.collectDeep(m) { case m: AddOne => m.toTarget }
+ })
+ intercept[Exception] { getFirrtlAndAnnos(new AddFour, Seq(aspect)) }
+ }
+ it("10.7: Select.getDeep should fail when combined with hierarchy package") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ aop.Select.getDeep(m) { m: BaseModule => Nil }
+ })
+ intercept[Exception] { getFirrtlAndAnnos(new AddFour, Seq(aspect)) }
+ }
+ it("10.8: Select.instances should fail when combined with hierarchy package") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ aop.Select.instances(m)
+ })
+ intercept[Exception] { getFirrtlAndAnnos(new AddFour, Seq(aspect)) }
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/util/BitPatSpec.scala b/src/test/scala/chiselTests/util/BitPatSpec.scala
index 0c83493f..549e8bca 100644
--- a/src/test/scala/chiselTests/util/BitPatSpec.scala
+++ b/src/test/scala/chiselTests/util/BitPatSpec.scala
@@ -24,10 +24,18 @@ class BitPatSpec extends AnyFlatSpec with Matchers {
intercept[IllegalArgumentException]{BitPat("b")}
}
- it should "contact BitPat via ##" in {
+ it should "concat BitPat via ##" in {
(BitPat.Y(4) ## BitPat.dontCare(3) ## BitPat.N(2)).toString should be (s"BitPat(1111???00)")
}
+ it should "throw when BitPat apply to a Hardware" in {
+ intercept[java.lang.IllegalArgumentException]{
+ chisel3.stage.ChiselStage.emitChirrtl(new chisel3.Module {
+ BitPat(chisel3.Reg(chisel3.Bool()))
+ })
+ }
+ }
+
it should "index and return new BitPat" in {
val b = BitPat("b1001???")
b(0) should be(BitPat.dontCare(1))
diff --git a/src/test/scala/chiselTests/util/BitSetSpec.scala b/src/test/scala/chiselTests/util/BitSetSpec.scala
new file mode 100644
index 00000000..8120cc97
--- /dev/null
+++ b/src/test/scala/chiselTests/util/BitSetSpec.scala
@@ -0,0 +1,119 @@
+package chiselTests.util
+
+import chisel3.util.experimental.BitSet
+import chisel3.util.BitPat
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+class BitSetSpec extends AnyFlatSpec with Matchers {
+ behavior of classOf[BitSet].toString
+
+ it should "reject unequal width when constructing a BitSet" in {
+ intercept[IllegalArgumentException] {
+ BitSet.fromString(
+ """b0010
+ |b00010
+ |""".stripMargin)
+ }
+ }
+
+ it should "return empty subtraction result correctly" in {
+ val aBitPat = BitPat("b10?")
+ val bBitPat = BitPat("b1??")
+
+ aBitPat.subtract(bBitPat).isEmpty should be (true)
+ }
+
+ it should "return nonempty subtraction result correctly" in {
+ val aBitPat = BitPat("b10?")
+ val bBitPat = BitPat("b1??")
+ val cBitPat = BitPat("b11?")
+ val dBitPat = BitPat("b100")
+
+ val diffBitPat = bBitPat.subtract(aBitPat)
+ bBitPat.cover(diffBitPat) should be (true)
+ diffBitPat.equals(cBitPat) should be (true)
+
+ val largerdiffBitPat = bBitPat.subtract(dBitPat)
+ aBitPat.cover(dBitPat) should be (true)
+ largerdiffBitPat.cover(diffBitPat) should be (true)
+ }
+
+ it should "be able to handle complex subtract between BitSet" in {
+ val aBitSet = BitSet.fromString(
+ """b?01?0
+ |b11111
+ |b00000
+ |""".stripMargin)
+ val bBitSet = BitSet.fromString(
+ """b?1111
+ |b?0000
+ |""".stripMargin
+ )
+ val expected = BitPat("b?01?0")
+
+ expected.equals(aBitSet.subtract(bBitSet)) should be (true)
+ }
+
+ it should "be generated from BitPat union" in {
+ val aBitSet = BitSet.fromString(
+ """b001?0
+ |b000??""".stripMargin)
+ val aBitPat = BitPat("b000??")
+ val bBitPat = BitPat("b001?0")
+ val cBitPat = BitPat("b00000")
+ aBitPat.cover(cBitPat) should be (true)
+ aBitSet.cover(bBitPat) should be (true)
+
+ aBitSet.equals(aBitPat.union(bBitPat)) should be (true)
+ }
+
+ it should "be generated from BitPat subtraction" in {
+ val aBitSet = BitSet.fromString(
+ """b001?0
+ |b000??""".stripMargin)
+ val aBitPat = BitPat("b00???")
+ val bBitPat = BitPat("b001?1")
+
+ aBitSet.equals(aBitPat.subtract(bBitPat)) should be (true)
+ }
+
+ it should "union two BitSet together" in {
+ val aBitSet = BitSet.fromString(
+ """b001?0
+ |b001?1
+ |""".stripMargin)
+ val bBitSet = BitSet.fromString(
+ """b000??
+ |b01???
+ |""".stripMargin
+ )
+ val cBitPat = BitPat("b0????")
+ cBitPat.equals(aBitSet.union(bBitSet)) should be (true)
+ }
+
+ it should "be decoded" in {
+ import chisel3._
+ import chisel3.util.experimental.decode.decoder
+ // [0 - 256] part into: [0 - 31], [32 - 47, 64 - 127], [192 - 255]
+ // "0011????" "10??????" is empty to error
+ chisel3.stage.ChiselStage.emitSystemVerilog(new Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(4.W)))
+ out := decoder.bitset(in, Seq(
+ BitSet.fromString(
+ "b000?????"
+ ),
+ BitSet.fromString(
+ """b0010????
+ |b01??????
+ |""".stripMargin
+ ),
+ BitSet.fromString(
+ "b11??????"
+ )
+ ), true)
+ })
+ }
+
+}
diff --git a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
index 743a3cd8..255effaf 100644
--- a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
+++ b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
@@ -2,8 +2,9 @@
package chiselTests.util.experimental
+import chisel3._
import chisel3.util.BitPat
-import chisel3.util.experimental.decode.TruthTable
+import chisel3.util.experimental.decode.{TruthTable, decoder}
import org.scalatest.flatspec.AnyFlatSpec
class TruthTableSpec extends AnyFlatSpec {
@@ -34,16 +35,16 @@ class TruthTableSpec extends AnyFlatSpec {
assert(table.toString contains " 0")
}
"TruthTable" should "deserialize" in {
- assert(TruthTable(str) == table)
+ assert(TruthTable.fromString(str) == table)
}
"TruthTable" should "merge same key" in {
assert(
- TruthTable(
+ TruthTable.fromString(
"""001100->??1
|001100->1??
|???
|""".stripMargin
- ) == TruthTable(
+ ) == TruthTable.fromString(
"""001100->1?1
|???
|""".stripMargin
@@ -52,7 +53,7 @@ class TruthTableSpec extends AnyFlatSpec {
}
"TruthTable" should "crash when merging 0 and 1" in {
intercept[IllegalArgumentException] {
- TruthTable(
+ TruthTable.fromString(
"""0->0
|0->1
|???
@@ -60,4 +61,24 @@ class TruthTableSpec extends AnyFlatSpec {
)
}
}
+ "TruthTable" should "be reproducible" in {
+ class Foo extends Module {
+
+ val io = IO(new Bundle{
+ val in = Input(UInt(4.W))
+ val out = Output(UInt(16.W))
+ })
+
+
+ val table = TruthTable(
+ (0 until 16).map{
+ i => BitPat(i.U(4.W)) -> BitPat((1<<i).U(16.W))
+ },
+ BitPat.dontCare(16)
+ )
+
+ io.out := decoder.qmc(io.in, table)
+ }
+ assert(chisel3.stage.ChiselStage.emitChirrtl(new Foo) == chisel3.stage.ChiselStage.emitChirrtl(new Foo))
+ }
}