summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorJack2021-12-18 08:27:38 +0000
committerJack2021-12-18 08:27:38 +0000
commitdd9ad534771247ac16eaa47eb9794102736b5102 (patch)
treed4566d317cb8526b79017de1e438aea8217dd1d4 /src/main
parent440edc4436fb3a8a4175ae425a0d31c4997ee60f (diff)
parentf50f74f583fba7b98e550c440df091e559ce32b8 (diff)
Merge branch 'master' into 3.5-release
Diffstat (limited to 'src/main')
-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
21 files changed, 814 insertions, 282 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 })
}