From d1d38bd096fce8b92468720fbedc835ecda40e6b Mon Sep 17 00:00:00 2001 From: Kevin Laeufer Date: Thu, 23 Sep 2021 11:12:26 -0700 Subject: make all verification statements publically available (#2089) --- src/main/scala/chisel3/aop/Select.scala | 2 +- .../experimental/verification/package.scala | 27 ++++++++++++++++++++++ src/main/scala/chisel3/testers/BasicTester.scala | 7 +----- 3 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 src/main/scala/chisel3/experimental/verification/package.scala (limited to 'src/main') diff --git a/src/main/scala/chisel3/aop/Select.scala b/src/main/scala/chisel3/aop/Select.scala index 2384c4d3..9c7320ce 100644 --- a/src/main/scala/chisel3/aop/Select.scala +++ b/src/main/scala/chisel3/aop/Select.scala @@ -269,7 +269,7 @@ object Select { 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 => } }) 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..f95b30bc --- /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.4") + 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.4") + 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.4") + 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/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. -- cgit v1.2.3 From 92f1ace73c85de859082eaa917eaacfce026fdf8 Mon Sep 17 00:00:00 2001 From: Kevin Laeufer Date: Thu, 23 Sep 2021 13:44:03 -0700 Subject: verification: fix off by one error in deprecation message (#2135) --- src/main/scala/chisel3/experimental/verification/package.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/experimental/verification/package.scala b/src/main/scala/chisel3/experimental/verification/package.scala index f95b30bc..a026542d 100644 --- a/src/main/scala/chisel3/experimental/verification/package.scala +++ b/src/main/scala/chisel3/experimental/verification/package.scala @@ -8,19 +8,19 @@ 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.4") + @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.4") + @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.4") + @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) } -- cgit v1.2.3 From ce15ad50a5c175db06c3bba5e3bf46b6c5466c47 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Tue, 5 Oct 2021 10:27:18 -0700 Subject: Remove all Bundle cloneTypes and chiselRuntimeDeprecate its use (#2052) * Remove all manual cloneTypes and make it chisel runtime deprecated to add one * runtime deprecate cloneType with runtime reflection * [Backport this commit] Bundle: add check that override def cloneType still works (will be made an error later) * Plugin: make it an error to override cloneType and add a test for that * Docs: can't compile the cloneType anymore * BundleSpec: comment out failing test I cannot get to fail or ignore Co-authored-by: Jack Koenig --- src/main/scala/chisel3/util/BitPat.scala | 1 - src/main/scala/chisel3/util/Decoupled.scala | 6 ------ src/main/scala/chisel3/util/Enum.scala | 1 - src/main/scala/chisel3/util/Valid.scala | 2 -- 4 files changed, 10 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index 0dcb2466..d607be4f 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -4,7 +4,6 @@ package chisel3.util import scala.language.experimental.macros import chisel3._ -import chisel3.internal.chiselRuntimeDeprecated import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 8909ffe3..0e05d114 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -82,9 +82,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 @@ -123,9 +120,6 @@ object Decoupled * @param gen the type of data to be wrapped in IrrevocableIO */ 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 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..838d43ca 100644 --- a/src/main/scala/chisel3/util/Valid.scala +++ b/src/main/scala/chisel3/util/Valid.scala @@ -29,8 +29,6 @@ class Valid[+T <: Data](gen: T) extends Bundle { * @return a Chisel [[Bool]] true if `valid` is asserted */ def fire(dummy: Int = 0): Bool = valid - - override def cloneType: this.type = Valid(gen).asInstanceOf[this.type] } /** Factory for generating "valid" interfaces. A "valid" interface is a data-communicating interface between a producer -- cgit v1.2.3 From 110705eeace4f9165dc6377e55c86a599f37a465 Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Tue, 5 Oct 2021 12:33:23 -0700 Subject: Deprecate auto-application of empty argument lists to parameterless functions (#2124) * Migrate nullary funcs to parameterless versions * Make deprecation message and dummy arguments clear and consistent Co-authored-by: Megan Wachs --- src/main/scala/chisel3/compatibility.scala | 5 ++++- src/main/scala/chisel3/util/Decoupled.scala | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index dde2321d..ffbb7e27 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) { diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 0e05d114..060a684c 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -37,7 +37,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. @@ -222,8 +225,8 @@ 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 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 -- cgit v1.2.3 From 7930544e9c8047f27285420204d25f78c753ea57 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Fri, 8 Oct 2021 09:07:04 -0700 Subject: Add nullary .fire to Valid and deprecate dummy version (#2156) Also replace all uses of .fire() with .fire--- src/main/scala/chisel3/util/Arbiter.scala | 4 ++-- src/main/scala/chisel3/util/Valid.scala | 3 +++ src/main/scala/chisel3/util/random/PRNG.scala | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/util/Arbiter.scala b/src/main/scala/chisel3/util/Arbiter.scala index 059bdd14..135700fa 100644 --- a/src/main/scala/chisel3/util/Arbiter.scala +++ b/src/main/scala/chisel3/util/Arbiter.scala @@ -47,7 +47,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 +63,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/Valid.scala b/src/main/scala/chisel3/util/Valid.scala index 838d43ca..4d348014 100644 --- a/src/main/scala/chisel3/util/Valid.scala +++ b/src/main/scala/chisel3/util/Valid.scala @@ -28,6 +28,9 @@ class Valid[+T <: Data](gen: T) extends Bundle { /** True when `valid` is asserted * @return a Chisel [[Bool]] true if `valid` is asserted */ + def fire: Bool = 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 = valid } diff --git a/src/main/scala/chisel3/util/random/PRNG.scala b/src/main/scala/chisel3/util/random/PRNG.scala index d94b78e8..9b42acf1 100644 --- a/src/main/scala/chisel3/util/random/PRNG.scala +++ b/src/main/scala/chisel3/util/random/PRNG.scala @@ -62,7 +62,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 }) } -- cgit v1.2.3 From ffa0831c736c7d5296964bc65536ac256220dcaa Mon Sep 17 00:00:00 2001 From: Nic McDonald Date: Tue, 12 Oct 2021 15:25:55 -0600 Subject: Fix GaloisLFSR comments (#2178) --- src/main/scala/chisel3/util/random/GaloisLFSR.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main') 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 -- cgit v1.2.3 From ef8a9c2148f01e058d2986c9d64f0c35f640790c Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Wed, 27 Oct 2021 16:52:56 -0700 Subject: Add Select APIs for Hierarchy package (#2210) * Add Hierarchy trait * Add Hierarchy trait * Add Hierarchy scaladoc * Add license * Add isA and tests * Add back isA * Add new Select APIs for hierarchy package * Update scaladoc * Write outlines for tests * Add tests and fixes to new Select functions * Make calculate via lazy val * Apply suggestions from code review Co-authored-by: Megan Wachs * Apply suggestions from code review Co-authored-by: Megan Wachs * Clean up scaladoc * Add shouldNot compile * Apply suggestions from code review Co-authored-by: Megan Wachs * Bugfix all funcs should analyze root too * Add mdoc, bugfix toDefinition * Make func private, add scaladoc * Update src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala Co-authored-by: Jack Koenig * Made protected vals private * Apply suggestions from code review Co-authored-by: Jack Koenig * Address code review comments * Added additional null check Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig --- src/main/scala/chisel3/aop/Select.scala | 178 ++++++++++++++++++--- .../chisel3/aop/injecting/InjectingAspect.scala | 2 +- 2 files changed, 156 insertions(+), 24 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/aop/Select.scala b/src/main/scala/chisel3/aop/Select.scala index 9c7320ce..8bdf4344 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(Right(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(Right(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(Left(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(Right(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,7 +396,6 @@ 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]() @@ -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) } -- cgit v1.2.3 From 0c43dadf60c1485be348115c20690990f0fea940 Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Thu, 28 Oct 2021 18:18:34 -0700 Subject: Exposing more APIs from D/I internals (#2220) Exposing more internals of D/I, which are required for supporting D/I with more powerful Chisel libraries: - Exposing IsClone[_] - Exposing InstantiableClone[_] - Gated builders for Instance/Definition - Unsealing Lookupable, with protected accessors for proto and cloned--- src/main/scala/chisel3/aop/Select.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/aop/Select.scala b/src/main/scala/chisel3/aop/Select.scala index 8bdf4344..8f5a2577 100644 --- a/src/main/scala/chisel3/aop/Select.scala +++ b/src/main/scala/chisel3/aop/Select.scala @@ -53,7 +53,7 @@ object Select { case d: DefInstance => d.id match { case p: chisel3.internal.BaseModule.IsClone[_] => - parent._lookup { x => new Instance(Right(p)).asInstanceOf[Instance[BaseModule]] } + parent._lookup { x => new Instance(Clone(p)).asInstanceOf[Instance[BaseModule]] } case other: BaseModule => parent._lookup { x => other } } @@ -75,7 +75,7 @@ object Select { case d: DefInstance => d.id match { case p: chisel3.internal.BaseModule.IsClone[_] => - val i = parent._lookup { x => new Instance(Right(p)).asInstanceOf[Instance[BaseModule]] } + 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 } @@ -111,7 +111,7 @@ object Select { case i: DefInstance => i.id match { case p: chisel3.internal.BaseModule.IsClone[_] => - parent._lookup { x => new Definition(Left(p.getProto)).asInstanceOf[Definition[BaseModule]] } + parent._lookup { x => new Definition(Proto(p.getProto)).asInstanceOf[Definition[BaseModule]] } case other: BaseModule => parent._lookup { x => other.toDefinition } } @@ -139,7 +139,7 @@ object Select { case d: DefInstance => d.id match { case p: chisel3.internal.BaseModule.IsClone[_] => - val d = parent._lookup { x => new Definition(Right(p)).asInstanceOf[Definition[BaseModule]] } + 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 } -- cgit v1.2.3 From a79f57565e7157d137628d1aaeae750f98e3d88b Mon Sep 17 00:00:00 2001 From: Abongwa Bonalais Date: Wed, 3 Nov 2021 05:56:37 +0100 Subject: Add field grouping ScalaDoc for other subclasses of Bundle (#2214) * Add field grouping scaladocs for DecoupledIo * Added groupdesc to DecoupledIO * Added groupings for IrrevocableIO * Add groupings for ValidIO * Add field grouping scaladoc for PRNGIO * Add field grouping scaladoc for QueueIO * Added groupings for PipeIO * Update src/main/scala/chisel3/util/Decoupled.scala Commited Sugestion Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Decoupled.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Decoupled.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Decoupled.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Decoupled.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Valid.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Valid.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Valid.scala Co-authored-by: Megan Wachs Co-authored-by: Megan Wachs --- src/main/scala/chisel3/util/Decoupled.scala | 30 +++++++++++++++++++++++---- src/main/scala/chisel3/util/Valid.scala | 18 ++++++++++++---- src/main/scala/chisel3/util/random/PRNG.scala | 13 +++++++++--- 3 files changed, 50 insertions(+), 11 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 060a684c..2a098f4d 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) } @@ -121,6 +133,7 @@ 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) @@ -161,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. @@ -169,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 } diff --git a/src/main/scala/chisel3/util/Valid.scala b/src/main/scala/chisel3/util/Valid.scala index 4d348014..5d80502a 100644 --- a/src/main/scala/chisel3/util/Valid.scala +++ b/src/main/scala/chisel3/util/Valid.scala @@ -17,12 +17,17 @@ 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 @@ -173,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/random/PRNG.scala b/src/main/scala/chisel3/util/random/PRNG.scala index 9b42acf1..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())) } -- cgit v1.2.3 From 614551236186d35ff42ea9c90130a3b80646ba69 Mon Sep 17 00:00:00 2001 From: Abongwa Bonalais Date: Wed, 3 Nov 2021 06:46:49 +0100 Subject: Add field grouping ScalaDoc for ArbiterIO (#2208) * Update Arbiter.scala * Update src/main/scala/chisel3/util/Arbiter.scala changed group name Co-authored-by: Megan Wachs * minor changes on grouping ArbiterIO * removed unmatched closing brace * Remove groupdesc from Arbiter.scala * Added groupdesc to Aggregate.scala * Update Arbiter.scala * Update core/src/main/scala/chisel3/Aggregate.scala Co-authored-by: Megan Wachs * Update Arbiter.scala * Update src/main/scala/chisel3/util/Arbiter.scala Added suugestions. Co-authored-by: Megan Wachs * added suggestions from review * added suggestions from review * Resolved conflicts * update Arbiter.scala * Update core/src/main/scala/chisel3/Aggregate.scala deleted groudesc for ArbiterIO Co-authored-by: Megan Wachs * Update Scaladoc syntax * removed some lines * Better documentation * Removed @param and @gen * Update core/src/main/scala/chisel3/Aggregate.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Arbiter.scala Co-authored-by: Megan Wachs * Added groupdesc to ArbiterIO * Update src/main/scala/chisel3/util/Arbiter.scala Co-authored-by: Megan Wachs * Update core/src/main/scala/chisel3/Aggregate.scala Co-authored-by: Megan Wachs * Update Arbiter.scala * Update src/main/scala/chisel3/util/Arbiter.scala Co-authored-by: Megan Wachs * Update Arbiter.scala Co-authored-by: Megan Wachs --- src/main/scala/chisel3/util/Arbiter.scala | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/main') diff --git a/src/main/scala/chisel3/util/Arbiter.scala b/src/main/scala/chisel3/util/Arbiter.scala index 135700fa..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)) } -- cgit v1.2.3 From d4aa92cef6b067ef6c1c37fc7fde467f0c815767 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Sun, 14 Nov 2021 04:29:00 +0800 Subject: add toBools to compatibility layer. --- src/main/scala/chisel3/compatibility.scala | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main') diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index ffbb7e27..d1e7b4f1 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -637,6 +637,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) } } -- cgit v1.2.3 From 8f796df5693b560a086b95a24c5bd090064a639e Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Thu, 18 Nov 2021 02:31:32 +0800 Subject: refactor Queue.hasFlush: Boolean to Queue.flush: Option[Bool]. (#2245) * refactor Queue.hasFlush: Boolean to Queue.flush: Option[Bool]. Using factory Queue(..., hasFlush = true) won't take effects, since in the Queue.apply API, Queue Module is not exposed, thus even user defines hasFlush = true, there is no place for them to give the flush signal. This commit fix this, refactor Queue.hasFlush: Boolean to Queue.flush: Option[Bool], makes user be able to pass the flush signal into Queue Module. * use zip to connect. * refactor docs. Co-authored-by: Megan Wachs --- src/main/scala/chisel3/util/Decoupled.scala | 65 +++++++++++++++++++---------- 1 file changed, 44 insertions(+), 21 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 2a098f4d..4b8b3eeb 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -249,7 +249,7 @@ class Queue[T <: Data](val gen: T, 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 flush = io.flush.getOrElse(false.B) // when flush is high, empty the queue // Semantically, any enqueues happen before the flush. @@ -307,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], @@ -328,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 @@ -336,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 @@ -344,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]( @@ -355,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 -- cgit v1.2.3 From 2b0bc0ecbc9c53882e2104ecd1e1387039be27f3 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Tue, 23 Nov 2021 04:17:14 +0800 Subject: add documentations to decoder. (#2254) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- .../chisel3/util/experimental/decode/EspressoMinimizer.scala | 12 +++++++++++- .../chisel3/util/experimental/decode/QMCMinimizer.scala | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala index 1d725875..6adf544c 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') diff --git a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala index c1533f44..8bd8a03e 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) -- cgit v1.2.3 From 563f6157a861d0f524a84d15fc8c2647c8cfb6ba Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Mon, 29 Nov 2021 11:39:00 -0800 Subject: Deprecate chisel3.BackendCompilationUtilities (#2257) Also remove as many deprecated APIs as possible by inlining implementations of old deprecated/removed code from firrtl--- src/main/scala/chisel3/Driver.scala | 145 +++++++++++++++++------------ src/main/scala/chisel3/compatibility.scala | 3 +- src/main/scala/chisel3/stage/package.scala | 29 ------ 3 files changed, 85 insertions(+), 92 deletions(-) (limited to 'src/main') 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/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index d1e7b4f1..ccb4ec1f 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -365,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 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)) - } - - } - - } - } -- cgit v1.2.3 From 40192433e96ffe91928fa140d32f99562f95e7cf Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Mon, 29 Nov 2021 16:02:04 -0800 Subject: Remove ChiselExecutionOptions and HasChiselExecutionOptions (#2267) These were not actually deprecated but any APIs using them were long since deprecated and more recently removed. They also depend on long deprecated APIs in FIRRTL that will soon be removed.--- .../scala/chisel3/ChiselExecutionOptions.scala | 49 ---------------------- .../chisel3/stage/phases/DriverCompatibility.scala | 16 +++---- 2 files changed, 5 insertions(+), 60 deletions(-) delete mode 100644 src/main/scala/chisel3/ChiselExecutionOptions.scala (limited to 'src/main') 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/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 -- cgit v1.2.3 From 08271081e4af2025fc6c6af97511fd110ef65e5c Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 8 Dec 2021 14:21:44 -0800 Subject: Implement DataViews for Seq and Tuple (#2277) * DataProducts for Seq and Tuple2-10 in DataProduct companion object * DataViews for Seq and Tuple 2-10 in DataView companion object * HWTuple2-10 Bundles in chisel3.experimental * Implicit conversions from Seq to Vec and Tuple to HWTuple in chisel3.experimental.conversions--- .../chisel3/experimental/conversions/package.scala | 128 +++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/main/scala/chisel3/experimental/conversions/package.scala (limited to 'src/main') 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]] + } +} -- cgit v1.2.3 From 849d4a0b7f6f7ea056c5280b9d319dadf5225022 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Thu, 9 Dec 2021 10:25:11 +0800 Subject: catch None.get in BitPat.apply(x: UInt): BitPat (#2276) Co-authored-by: Jack Koenig --- src/main/scala/chisel3/util/BitPat.scala | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index d607be4f..4b94879f 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -89,6 +89,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) } -- cgit v1.2.3 From 36506c527ff0f51636beee4160f0ce1f6ad2f90a Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Wed, 15 Dec 2021 15:53:52 +0800 Subject: Refactor TruthTable to use Seq (#2217) This makes the resulting Verilog from decoding a TruthTable deterministic.--- src/main/scala/chisel3/util/BitPat.scala | 6 +++ .../experimental/decode/EspressoMinimizer.scala | 3 +- .../util/experimental/decode/QMCMinimizer.scala | 10 ++--- .../util/experimental/decode/TruthTable.scala | 47 +++++++++++----------- .../chisel3/util/experimental/decode/decoder.scala | 2 +- 5 files changed, 36 insertions(+), 32 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index 4b94879f..4f8ae504 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -8,6 +8,12 @@ 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 diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala index 6adf544c..4dcea99e 100644 --- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala @@ -55,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 @@ -63,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 8bd8a03e..59120221 100644 --- a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala @@ -234,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 @@ -291,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) { @@ -300,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..ee2ece48 100644 --- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala +++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala @@ -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)) -- cgit v1.2.3 From 214115a4cdbf0714d3d1716035f5eb0dd98cba45 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Thu, 16 Dec 2021 09:47:05 +0800 Subject: BitSet API (#2211) BitSet is a new experimental parent type for BitPat. It enables more complex operations on BitPats. Co-authored-by: Ocean Shen --- src/main/scala/chisel3/util/BitPat.scala | 210 +++++++++++++++++++-- .../chisel3/util/experimental/decode/decoder.scala | 33 +++- 2 files changed, 228 insertions(+), 15 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index 4f8ae504..808245de 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -117,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. * @@ -126,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 = { @@ -167,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/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala index ee2ece48..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 @@ -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") + ) + ) } -- cgit v1.2.3