summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-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
5 files changed, 335 insertions, 145 deletions
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 }
+ }
+}