summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Lawson2016-12-19 10:20:48 -0800
committerGitHub2016-12-19 10:20:48 -0800
commitdd4650d29ed18ec610ad7561f4e9c990ba887a3d (patch)
tree333fe66fba7ea7337fa1f6ffe1ec905cd2f724f3 /src
parent207da69768dac464a719a7c712f6977371f7c5f4 (diff)
parent0233f704e83d380b1fe8311dfffa3f44f74b506b (diff)
Merge branch 'master' into exceptionfix
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/chisel3/Driver.scala20
-rw-r--r--src/main/scala/chisel3/package.scala3
-rw-r--r--src/main/scala/chisel3/util/BitPat.scala19
-rw-r--r--src/main/scala/chisel3/util/Bitwise.scala46
-rw-r--r--src/main/scala/chisel3/util/Cat.scala13
-rw-r--r--src/main/scala/chisel3/util/CircuitMath.scala17
-rw-r--r--src/main/scala/chisel3/util/Decoupled.scala5
-rw-r--r--src/test/scala/chiselTests/AnnotatingDiamondSpec.scala163
-rw-r--r--src/test/scala/chiselTests/AnnotatingExample.scala145
-rw-r--r--src/test/scala/chiselTests/AnnotationNoDedup.scala78
-rw-r--r--src/test/scala/cookbook/FSM.scala61
-rw-r--r--src/test/scala/cookbook/RegOfVec.scala33
12 files changed, 438 insertions, 165 deletions
diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala
index ab51ad25..40c94b54 100644
--- a/src/main/scala/chisel3/Driver.scala
+++ b/src/main/scala/chisel3/Driver.scala
@@ -6,10 +6,13 @@ import chisel3.internal.firrtl.Emitter
import scala.sys.process._
import java.io._
+import net.jcazevedo.moultingyaml._
import internal.firrtl._
import firrtl._
+import _root_.firrtl.annotations.AnnotationYamlProtocol._
+
/**
* The Driver provides methods to invoke the chisel3 compiler and the firrtl compiler.
* By default firrtl is automatically run after chisel. an [[ExecutionOptionsManager]]
@@ -239,6 +242,23 @@ object Driver extends BackendCompilationUtilities {
w.write(firrtlString)
w.close()
+ val annotationFile = new File(optionsManager.getBuildFileName("anno"))
+ val af = new FileWriter(annotationFile)
+ af.write(circuit.annotations.toArray.toYaml.prettyPrint)
+ af.close()
+
+ /* create custom transforms by finding the set of transform classes associated with annotations
+ * then instantiate them into actual transforms
+ */
+ val transforms = circuit.annotations.map(_.transform).toSet.map { transformClass: Class[_ <: Transform] =>
+ transformClass.newInstance()
+ }
+ /* This passes the firrtl source and annotations directly to firrtl */
+ optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy(
+ firrtlSource = Some(firrtlString),
+ annotations = circuit.annotations.toList,
+ customTransforms = transforms.toList)
+
val firrtlExecutionResult = if(chiselOptions.runFirrtlCompiler) {
Some(firrtl.Driver.execute(optionsManager))
}
diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala
index e4e64b89..25d3ec3a 100644
--- a/src/main/scala/chisel3/package.scala
+++ b/src/main/scala/chisel3/package.scala
@@ -32,6 +32,9 @@ package object chisel3 { // scalastyle:ignore package.object.name
type Element = chisel3.core.Element
type Bits = chisel3.core.Bits
+ type ChiselAnnotation = chisel3.core.ChiselAnnotation
+ val ChiselAnnotation = chisel3.core.ChiselAnnotation
+
// Some possible regex replacements for the literal specifier deprecation:
// (note: these are not guaranteed to handle all edge cases! check all replacements!)
// Bool\((true|false)\)
diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala
index 9c9909cd..add40f79 100644
--- a/src/main/scala/chisel3/util/BitPat.scala
+++ b/src/main/scala/chisel3/util/BitPat.scala
@@ -35,7 +35,7 @@ object BitPat {
}
/** Creates a [[BitPat]] literal from a string.
- *
+ *
* @param n the literal value as a string, in binary, prefixed with 'b'
* @note legal characters are '0', '1', and '?', as well as '_' and white
* space (which are ignored)
@@ -45,7 +45,12 @@ object BitPat {
new BitPat(bits, mask, width)
}
- /** Creates a [[BitPat]] of all don't cares of the specified bitwidth. */
+ /** Creates a [[BitPat]] of all don't cares of the specified bitwidth.
+ *
+ * @example {{{
+ * val myDontCare = BitPat.dontCare(4) // equivalent to BitPat("b????")
+ * }}}
+ */
def dontCare(width: Int): BitPat = BitPat("b" + ("?" * width))
@deprecated("Use BitPat.dontCare", "chisel3")
@@ -73,10 +78,14 @@ object BitPat {
}
}
-// TODO: Break out of Core? (this doesn't involve FIRRTL generation)
/** Bit patterns are literals with masks, used to represent values with don't
- * cares. Equality comparisons will ignore don't care bits (for example,
- * BitPat(0b10?1) === 0b1001.asUInt and 0b1011.asUInt.
+ * care bits. Equality comparisons will ignore don't care bits.
+ *
+ * @example {{{
+ * "b10101".U === BitPat("b101??") // evaluates to true.B
+ * "b10111".U === BitPat("b101??") // evaluates to true.B
+ * "b10001".U === BitPat("b101??") // evaluates to false.B
+ * }}}
*/
sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) {
def getWidth: Int = width
diff --git a/src/main/scala/chisel3/util/Bitwise.scala b/src/main/scala/chisel3/util/Bitwise.scala
index 22326972..950fa65f 100644
--- a/src/main/scala/chisel3/util/Bitwise.scala
+++ b/src/main/scala/chisel3/util/Bitwise.scala
@@ -8,11 +8,21 @@ package chisel3.util
import chisel3._
import chisel3.core.SeqUtils
+/** Creates repetitions of each bit of the input in order.
+ *
+ * @example {{{
+ * FillInterleaved(2, "b1 0 0 0".U) // equivalent to "b11 00 00 00".U
+ * FillInterleaved(2, "b1 0 0 1".U) // equivalent to "b11 00 00 11".U
+ * FillInterleaved(2, myUIntWire) // dynamic interleaved fill
+ *
+ * FillInterleaved(2, Seq(true.B, false.B, false.B, false.B)) // equivalent to "b11 00 00 00".U
+ * FillInterleaved(2, Seq(true.B, false.B, false.B, true.B)) // equivalent to "b11 00 00 11".U
+ * }}}
+ */
object FillInterleaved {
/** Creates n repetitions of each bit of x in order.
*
* Output data-equivalent to in(size(in)-1) (n times) ## ... ## in(1) (n times) ## in(0) (n times)
- * For example, FillInterleaved(2, "b1000") === UInt("b11 00 00 00")
*/
def apply(n: Int, in: UInt): UInt = apply(n, in.toBools)
@@ -23,14 +33,31 @@ object FillInterleaved {
def apply(n: Int, in: Seq[Bool]): UInt = Cat(in.map(Fill(n, _)).reverse)
}
-/** Returns the number of bits set (i.e value is 1) in the input signal.
+/** Returns the number of bits set (value is 1 or true) in the input signal.
+ *
+ * @example {{{
+ * PopCount(Seq(true.B, false.B, true.B, true.B)) // evaluates to 3.U
+ * PopCount(Seq(false.B, false.B, true.B, false.B)) // evaluates to 1.U
+ *
+ * PopCount("b1011".U) // evaluates to 3.U
+ * PopCount("b0010".U) // evaluates to 1.U
+ * PopCount(myUIntWire) // dynamic count
+ * }}}
*/
-object PopCount
-{
+object PopCount {
def apply(in: Iterable[Bool]): UInt = SeqUtils.count(in.toSeq)
+
def apply(in: Bits): UInt = apply((0 until in.getWidth).map(in(_)))
}
+/** Create repetitions of the input using a tree fanout topology.
+ *
+ * @example {{{
+ * Fill(2, "b1000".U) // equivalent to "b1000 1000".U
+ * Fill(2, "b1001".U) // equivalent to "b1001 1001".U
+ * Fill(2, myUIntWire) // dynamic fill
+ * }}}
+ */
object Fill {
/** Create n repetitions of x using a tree fanout topology.
*
@@ -53,6 +80,14 @@ object Fill {
}
}
+/** Returns the input in bit-reversed order. Useful for little/big-endian conversion.
+ *
+ * @example {{{
+ * Reverse("b1101".U) // equivalent to "b1011".U
+ * Reverse("b1101".U(8.W)) // equivalent to "b10110000".U
+ * Reverse(myUIntWire) // dynamic reverse
+ * }}}
+ */
object Reverse {
private def doit(in: UInt, length: Int): UInt = {
if (length == 1) {
@@ -73,7 +108,6 @@ object Reverse {
Cat(doit(in(half-1,0), half), doit(in(length-1,half), length-half))
}
}
- /** Returns the input in bit-reversed order. Useful for little/big-endian conversion.
- */
+
def apply(in: UInt): UInt = doit(in, in.getWidth)
}
diff --git a/src/main/scala/chisel3/util/Cat.scala b/src/main/scala/chisel3/util/Cat.scala
index ba12a7d4..78801541 100644
--- a/src/main/scala/chisel3/util/Cat.scala
+++ b/src/main/scala/chisel3/util/Cat.scala
@@ -5,8 +5,19 @@ package chisel3.util
import chisel3._
import chisel3.core.SeqUtils
+/** Concatenates elements of the input, in order, together.
+ *
+ * @example {{{
+ * Cat("b101".U, "b11".U) // equivalent to "b101 11".U
+ * Cat(myUIntWire0, myUIntWire1)
+ *
+ * Cat(Seq("b101".U, "b11".U)) // equivalent to "b101 11".U
+ * Cat(mySeqOfBits)
+ * }}}
+ */
object Cat {
- /** Concatenates the argument data elements, in argument order, together.
+ /** Concatenates the argument data elements, in argument order, together. The first argument
+ * forms the most significant bits, while the last argument forms the least significant bits.
*/
def apply[T <: Bits](a: T, r: T*): UInt = apply(a :: r.toList)
diff --git a/src/main/scala/chisel3/util/CircuitMath.scala b/src/main/scala/chisel3/util/CircuitMath.scala
index a422b5fe..b5f491ef 100644
--- a/src/main/scala/chisel3/util/CircuitMath.scala
+++ b/src/main/scala/chisel3/util/CircuitMath.scala
@@ -7,10 +7,19 @@ package chisel3.util
import chisel3._
+/** Returns the base-2 integer logarithm of an UInt.
+ *
+ * @note The result is truncated, so e.g. Log2(13.U) === 3.U
+ *
+ * @example {{{
+ * Log2(8.U) // evaluates to 3.U
+ * Log2(13.U) // evaluates to 3.U (truncation)
+ * Log2(myUIntWire)
+ * }}}
+ *
+ */
object Log2 {
/** Returns the base-2 integer logarithm of the least-significant `width` bits of an UInt.
- *
- * @note The result is truncated, so e.g. Log2(13.U) === 3.U
*/
def apply(x: Bits, width: Int): UInt = {
if (width < 2) {
@@ -28,10 +37,6 @@ object Log2 {
}
}
- /** Returns the base-2 integer logarithm of an UInt.
- *
- * @note The result is truncated, so e.g. Log2(13.U) === 3.U
- */
def apply(x: Bits): UInt = apply(x, x.getWidth)
private def divideAndConquerThreshold = 4
diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala
index fcda6943..4a97724a 100644
--- a/src/main/scala/chisel3/util/Decoupled.scala
+++ b/src/main/scala/chisel3/util/Decoupled.scala
@@ -37,12 +37,13 @@ object ReadyValidIO {
dat
}
- /** Indicate no enqueue occurs. Valid is set to false, and all bits are set to zero.
+ /** Indicate no enqueue occurs. Valid is set to false, and bits are
+ * connected to an uninitialized wire
*/
def noenq(): Unit = {
target.valid := false.B
// We want the type from the following, not any existing binding.
- target.bits := target.bits.cloneType.fromBits(0.asUInt)
+ target.bits := Wire(target.bits.cloneType)
}
/** Assert ready on this port and return the associated data bits.
diff --git a/src/test/scala/chiselTests/AnnotatingDiamondSpec.scala b/src/test/scala/chiselTests/AnnotatingDiamondSpec.scala
new file mode 100644
index 00000000..ff9f8e67
--- /dev/null
+++ b/src/test/scala/chiselTests/AnnotatingDiamondSpec.scala
@@ -0,0 +1,163 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import chisel3._
+import chisel3.internal.InstanceId
+import chisel3.testers.BasicTester
+import firrtl.{CircuitForm, CircuitState, LowForm, Transform}
+import firrtl.annotations.{Annotation, ModuleName, Named}
+import org.scalatest._
+
+//scalastyle:off magic.number
+/**
+ * This and the Identity transform class are a highly schematic implementation of a
+ * library implementation of (i.e. code outside of firrtl itself)
+ */
+object IdentityAnnotation {
+ def apply(target: Named, value: String): Annotation = Annotation(target, classOf[IdentityTransform], value)
+
+ def unapply(a: Annotation): Option[(Named, String)] = a match {
+ case Annotation(named, t, value) if t == classOf[IdentityTransform] => Some((named, value))
+ case _ => None
+ }
+}
+
+class IdentityTransform extends Transform {
+ override def inputForm: CircuitForm = LowForm
+
+ override def outputForm: CircuitForm = LowForm
+
+ override def execute(state: CircuitState): CircuitState = {
+ getMyAnnotations(state) match {
+ case Nil => state
+ case myAnnotations =>
+ state
+ }
+ }
+}
+
+trait IdentityAnnotator {
+ self: Module =>
+ def identify(component: InstanceId, value: String): Unit = {
+ annotate(ChiselAnnotation(component, classOf[IdentityTransform], value))
+ }
+}
+/** A diamond circuit Top instantiates A and B and both A and B instantiate C
+ * Illustrations of annotations of various components and modules in both
+ * relative and absolute cases
+ *
+ * This is currently not much of a test, read the printout to see what annotations look like
+ */
+/**
+ * This class has parameterizable widths, it will generate different hardware
+ * @param widthC io width
+ */
+class ModC(widthC: Int) extends Module with IdentityAnnotator {
+ val io = IO(new Bundle {
+ val in = Input(UInt(widthC.W))
+ val out = Output(UInt(widthC.W))
+ })
+ io.out := io.in
+
+ identify(this, s"ModC($widthC)")
+
+ identify(io.out, s"ModC(ignore param)")
+}
+
+/**
+ * instantiates a C of a particular size, ModA does not generate different hardware
+ * based on it's parameter
+ * @param annoParam parameter is only used in annotation not in circuit
+ */
+class ModA(annoParam: Int) extends Module with IdentityAnnotator {
+ val io = IO(new Bundle {
+ val in = Input(UInt())
+ val out = Output(UInt())
+ })
+ val modC = Module(new ModC(16))
+ modC.io.in := io.in
+ io.out := modC.io.out
+
+ identify(this, s"ModA(ignore param)")
+
+ identify(io.out, s"ModA.io.out($annoParam)")
+ identify(io.out, s"ModA.io.out(ignore_param)")
+}
+
+class ModB(widthB: Int) extends Module with IdentityAnnotator{
+ val io = IO(new Bundle {
+ val in = Input(UInt(widthB.W))
+ val out = Output(UInt(widthB.W))
+ })
+ val modC = Module(new ModC(widthB))
+ modC.io.in := io.in
+ io.out := modC.io.out
+
+ identify(io.in, s"modB.io.in annotated from inside modB")
+}
+
+class TopOfDiamond extends Module with IdentityAnnotator {
+ val io = IO(new Bundle {
+ val in = Input(UInt(32.W))
+ val out = Output(UInt(32.W))
+ })
+ val x = Reg(UInt(32.W))
+ val y = Reg(UInt(32.W))
+
+ val modA = Module(new ModA(64))
+ val modB = Module(new ModB(32))
+
+ x := io.in
+ modA.io.in := x
+ modB.io.in := x
+
+ y := modA.io.out + modB.io.out
+ io.out := y
+
+ identify(this, s"TopOfDiamond\nWith\nSome new lines")
+
+ identify(modB.io.in, s"modB.io.in annotated from outside modB")
+}
+
+class DiamondTester extends BasicTester {
+ val dut = Module(new TopOfDiamond)
+
+ stop()
+}
+
+class AnnotatingDiamondSpec extends FreeSpec with Matchers {
+ def findAnno(as: Seq[Annotation], name: String): Option[Annotation] = {
+ as.find { a => a.targetString == name }
+ }
+
+ """
+ |Diamond is an example of a module that has two sub-modules A and B who both instantiate their
+ |own instances of module C. This highlights the difference between specific and general
+ |annotation scopes
+ """.stripMargin - {
+
+ """
+ |annotations are not resolved at after circuit elaboration,
+ |that happens only after emit has been called on circuit""".stripMargin in {
+
+ Driver.execute(Array.empty[String], () => new TopOfDiamond) match {
+ case ChiselExecutionSucccess(Some(circuit), emitted, _) =>
+ val annos = circuit.annotations
+ annos.length should be (10)
+
+ annos.count {
+ case Annotation(ModuleName(name, _), _, annoValue) => name == "ModC" && annoValue == "ModC(16)"
+ case _ => false
+ } should be (1)
+
+ annos.count {
+ case Annotation(ModuleName(name, _), _, annoValue) => name == "ModC_1" && annoValue == "ModC(32)"
+ case _ => false
+ } should be (1)
+ case _ =>
+ assert(false)
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/test/scala/chiselTests/AnnotatingExample.scala b/src/test/scala/chiselTests/AnnotatingExample.scala
deleted file mode 100644
index 0be3ba59..00000000
--- a/src/test/scala/chiselTests/AnnotatingExample.scala
+++ /dev/null
@@ -1,145 +0,0 @@
-// See LICENSE for license details.
-
-package chiselTests
-
-import chisel3._
-import chisel3.core.Module
-import chisel3.internal.InstanceId
-import chisel3.testers.BasicTester
-import org.scalatest._
-
-import scala.util.DynamicVariable
-
-//scalastyle:off magic.number
-
-/**
- * This Spec file illustrates use of Donggyu's component name API, it currently only
- * uses three methods .signalName, .parentModName and .pathName
- *
- * This is also an illustration of how to implement an annotation system in chisel3
- * A local (my) Driver and Builder are created to provide thread-local access to
- * an annotation map, and then a post elaboration annotation processor can resolve
- * the keys and could serialize the annotations to a file for use by firrtl passes
- */
-
-class SomeSubMod(param1: Int, param2: Int) extends Module {
- val io = new Bundle {
- val in = Input(UInt(16.W))
- val out = Output(SInt(32.W))
- }
- val annotate = MyBuilder.myDynamicContext.annotationMap
-
- annotate(AnnotationKey(this, JustThisRef)) = s"SomeSubMod($param1, $param2)"
- annotate(AnnotationKey(io.in, AllRefs)) = "sub mod io.in"
- annotate(AnnotationKey(io.out, JustThisRef)) = "sub mod io.out"
-}
-
-class AnnotatingExample extends Module {
- val io = new Bundle {
- val a = Input(UInt(32.W))
- val b = Input(UInt(32.W))
- val e = Input(Bool())
- val z = Output(UInt(32.W))
- val v = Output(Bool())
- val bun = new Bundle {
- val nested_1 = Input(UInt(12.W))
- val nested_2 = Output(Bool())
- }
- }
- val x = Reg(UInt(32.W))
- val y = Reg(UInt(32.W))
-
- val subModule1 = Module(new SomeSubMod(1, 2))
- val subModule2 = Module(new SomeSubMod(3, 4))
-
-
- val annotate = MyBuilder.myDynamicContext.annotationMap
-
- annotate(AnnotationKey(subModule2, AllRefs)) = s"SomeSubMod was used"
-
- annotate(AnnotationKey(x, JustThisRef)) = "I am register X"
- annotate(AnnotationKey(y, AllRefs)) = "I am register Y"
- annotate(AnnotationKey(io.a, JustThisRef)) = "I am io.a"
- annotate(AnnotationKey(io.bun.nested_1, AllRefs)) = "I am io.bun.nested_1"
- annotate(AnnotationKey(io.bun.nested_2, JustThisRef)) = "I am io.bun.nested_2"
-}
-
-class AnnotatingExampleTester extends BasicTester {
- val dut = Module(new AnnotatingExample)
-
- stop()
-}
-
-class AnnotatingExampleSpec extends FlatSpec with Matchers {
- behavior of "Annotating components of a circuit"
-
- it should "contain the following relative keys" in {
- val annotationMap = MyDriver.buildAnnotatedCircuit { () => new AnnotatingExampleTester }
-
- annotationMap.contains("SomeSubMod.io.in") should be(true)
- annotationMap.contains("AnnotatingExample.y") should be(true)
-
- annotationMap("SomeSubMod.io.in") should be("sub mod io.in")
- }
- it should "contain the following absolute keys" in {
- val annotationMap = MyDriver.buildAnnotatedCircuit { () => new AnnotatingExampleTester }
-
- annotationMap.contains("AnnotatingExampleTester.dut.subModule2.io.out") should be (true)
- annotationMap.contains("AnnotatingExampleTester.dut.x") should be (true)
-
- annotationMap("AnnotatingExampleTester.dut.subModule2.io.out") should be ("sub mod io.out")
- }
-}
-
-trait AnnotationScope
-case object AllRefs extends AnnotationScope
-case object JustThisRef extends AnnotationScope
-
-object AnnotationKey {
- def apply(component: InstanceId): AnnotationKey = {
- AnnotationKey(component, AllRefs)
- }
-}
-case class AnnotationKey(val component: InstanceId, scope: AnnotationScope) {
- override def toString: String = {
- scope match {
- case JustThisRef =>
- s"${component.pathName}"
- case AllRefs =>
- s"${component.parentModName}.${component.instanceName}"
- case _ =>
- s"${component.toString}_unknown_scope"
- }
- }
-}
-
-class AnnotationMap extends scala.collection.mutable.HashMap[AnnotationKey, String]
-
-class MyDynamicContext {
- val annotationMap = new AnnotationMap
-}
-
-object MyBuilder {
- private val myDynamicContextVar = new DynamicVariable[Option[MyDynamicContext]](None)
-
- def myDynamicContext: MyDynamicContext =
- myDynamicContextVar.value getOrElse new MyDynamicContext
-
- def processAnnotations(annotationMap: AnnotationMap): Map[String, String] = {
- annotationMap.map { case (k,v) => k.toString -> v}.toMap
- }
-
- def build[T <: Module](f: => T): Map[String, String] = {
- myDynamicContextVar.withValue(Some(new MyDynamicContext)) {
- Driver.emit(() => f)
- processAnnotations(myDynamicContextVar.value.get.annotationMap)
- }
- }
-}
-
-object MyDriver extends BackendCompilationUtilities {
- /**
- * illustrates a chisel3 style driver that, annotations can only processed within this structure
- */
- def buildAnnotatedCircuit[T <: Module](gen: () => T): Map[String, String] = MyBuilder.build(gen())
-}
diff --git a/src/test/scala/chiselTests/AnnotationNoDedup.scala b/src/test/scala/chiselTests/AnnotationNoDedup.scala
new file mode 100644
index 00000000..024b5a7a
--- /dev/null
+++ b/src/test/scala/chiselTests/AnnotationNoDedup.scala
@@ -0,0 +1,78 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import chisel3._
+import firrtl.FirrtlExecutionSuccess
+import firrtl.transforms.DedupModules
+import org.scalatest.{FreeSpec, Matchers}
+
+trait NoDedupAnnotator {
+ self: Module =>
+
+ def doNotDedup(module: Module): Unit = {
+ annotate(ChiselAnnotation(module, classOf[DedupModules], "nodedup!"))
+ }
+}
+
+class MuchUsedModule extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+ io.out := io.in +% 1.U
+}
+
+class UsesMuchUsedModule(addAnnos: Boolean) extends Module with NoDedupAnnotator{
+ val io = IO(new Bundle {
+ val in = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+
+ val mod0 = Module(new MuchUsedModule)
+ val mod1 = Module(new MuchUsedModule)
+ val mod2 = Module(new MuchUsedModule)
+ val mod3 = Module(new MuchUsedModule)
+
+ mod0.io.in := io.in
+ mod1.io.in := mod0.io.out
+ mod2.io.in := mod1.io.out
+ mod3.io.in := mod2.io.out
+ io.out := mod3.io.out
+
+ if(addAnnos) {
+ doNotDedup(mod1)
+ doNotDedup(mod3)
+ }
+}
+
+class AnnotationNoDedup extends FreeSpec with Matchers {
+ "Firrtl provides transform that reduces identical modules to a single instance" - {
+ "Annotations can be added which will defeat this deduplication for specific modules instances" in {
+ Driver.execute(Array("-X", "low"), () => new UsesMuchUsedModule(addAnnos = true)) match {
+ case ChiselExecutionSucccess(_, _, Some(firrtlResult: FirrtlExecutionSuccess)) =>
+ val lowFirrtl = firrtlResult.emitted
+
+ lowFirrtl should include ("module MuchUsedModule :")
+ lowFirrtl should include ("module MuchUsedModule_1 :")
+ lowFirrtl should include ("module MuchUsedModule_3 :")
+ lowFirrtl should not include "module MuchUsedModule_2 :"
+ lowFirrtl should not include "module MuchUsedModule_4 :"
+ case _ =>
+ }
+ }
+ "Turning off these nnotations dedup all the occurrences" in {
+ Driver.execute(Array("-X", "low"), () => new UsesMuchUsedModule(addAnnos = false)) match {
+ case ChiselExecutionSucccess(_, _, Some(firrtlResult: FirrtlExecutionSuccess)) =>
+ val lowFirrtl = firrtlResult.emitted
+
+ lowFirrtl should include ("module MuchUsedModule :")
+ lowFirrtl should not include "module MuchUsedModule_1 :"
+ lowFirrtl should not include "module MuchUsedModule_3 :"
+ lowFirrtl should not include "module MuchUsedModule_2 :"
+ lowFirrtl should not include "module MuchUsedModule_4 :"
+ case _ =>
+ }
+ }
+ }
+}
diff --git a/src/test/scala/cookbook/FSM.scala b/src/test/scala/cookbook/FSM.scala
new file mode 100644
index 00000000..58f6a9a2
--- /dev/null
+++ b/src/test/scala/cookbook/FSM.scala
@@ -0,0 +1,61 @@
+// See LICENSE for license details.
+
+package cookbook
+
+import chisel3._
+import chisel3.util._
+
+/* ### How do I create a finite state machine?
+
+ * Use Chisel Enum to construct the states and switch & is to construct the FSM
+ * control logic
+ */
+class DetectTwoOnes extends Module {
+ val io = IO(new Bundle {
+ val in = Input(Bool())
+ val out = Output(Bool())
+ })
+
+ val sNone :: sOne1 :: sTwo1s :: Nil = Enum(3)
+ val state = Reg(init = sNone)
+
+ io.out := (state === sTwo1s)
+
+ switch (state) {
+ is (sNone) {
+ when (io.in) {
+ state := sOne1
+ }
+ }
+ is (sOne1) {
+ when (io.in) {
+ state := sTwo1s
+ } .otherwise {
+ state := sNone
+ }
+ }
+ is (sTwo1s) {
+ when (!io.in) {
+ state := sNone
+ }
+ }
+ }
+}
+
+class DetectTwoOnesTester extends CookbookTester(10) {
+
+ val dut = Module(new DetectTwoOnes)
+
+ // Inputs and expected results
+ val inputs: Vec[Bool] = Vec(false.B, true.B, false.B, true.B, true.B, true.B, false.B, true.B, true.B, false.B)
+ val expected: Vec[Bool] = Vec(false.B, false.B, false.B, false.B, false.B, true.B, true.B, false.B, false.B, true.B)
+
+ dut.io.in := inputs(cycle)
+ assert(dut.io.out === expected(cycle))
+}
+
+class FSMSpec extends CookbookSpec {
+ "DetectTwoOnes" should "work" in {
+ assertTesterPasses { new DetectTwoOnesTester }
+ }
+}
diff --git a/src/test/scala/cookbook/RegOfVec.scala b/src/test/scala/cookbook/RegOfVec.scala
new file mode 100644
index 00000000..3e55acff
--- /dev/null
+++ b/src/test/scala/cookbook/RegOfVec.scala
@@ -0,0 +1,33 @@
+// See LICENSE for license details.
+
+package cookbook
+
+import chisel3._
+
+/* ### How do I create a Reg of type Vec?
+ *
+ * For information, please see the API documentation for Vec
+ * (https://chisel.eecs.berkeley.edu/api/index.html#chisel3.core.Vec)
+ */
+class RegOfVec extends CookbookTester(2) {
+ // Reg of Vec of 32-bit UInts without initialization
+ val regOfVec = Reg(Vec(4, UInt(32.W)))
+ regOfVec(0) := 123.U // a couple of assignments
+ regOfVec(2) := regOfVec(0)
+
+ // Reg of Vec of 32-bit UInts initialized to zero
+ // Note that Seq.fill constructs 4 32-bit UInt literals with the value 0
+ // Vec(...) then constructs a Wire of these literals
+ // The Reg is then initialized to the value of the Wire (which gives it the same type)
+ val initRegOfVec = Reg(init = Vec(Seq.fill(4)(0.asUInt(32.W))))
+
+ // Simple test (cycle comes from superclass)
+ when (cycle === 2.U) { assert(regOfVec(2) === 123.U) }
+ for (elt <- initRegOfVec) { assert(elt === 0.U) }
+}
+
+class RegOfVecSpec extends CookbookSpec {
+ "RegOfVec" should "work" in {
+ assertTesterPasses { new RegOfVec }
+ }
+}