diff options
Diffstat (limited to 'src/test/scala/chiselTests/AnnotatingDiamondSpec.scala')
| -rw-r--r-- | src/test/scala/chiselTests/AnnotatingDiamondSpec.scala | 163 |
1 files changed, 163 insertions, 0 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 |
