diff options
| author | Albert Chen | 2019-02-22 15:30:27 -0800 |
|---|---|---|
| committer | mergify[bot] | 2019-02-22 23:30:27 +0000 |
| commit | 5608aa8f42c1d69b59bee158d14fc6cef9b19a47 (patch) | |
| tree | 86b7bad9c5f164d12aba9f324bde223e7ff5e9f3 /src/test/scala/firrtlTests/transforms | |
| parent | 0ace0218d3151df2d102463dd682128a88ae7be6 (diff) | |
Add Width Constraints with Annotations (#956)
* refactor InferWidths to allow for extra contraints, add InferWidthsWithAnnos
* add test cases
* add ResolvedAnnotationPaths trait to InferWidthsWithAnnos
* remove println
* cleanup tests
* remove extraneous constraints
* use foreachStmt instead of mapStmt
* remove support for aggregates
* fold InferWidthsWithAnnos into InferWidths
* throw exception if ref not found, check for annos before AST walk
Diffstat (limited to 'src/test/scala/firrtlTests/transforms')
| -rw-r--r-- | src/test/scala/firrtlTests/transforms/InferWidthsWithAnnosSpec.scala | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/src/test/scala/firrtlTests/transforms/InferWidthsWithAnnosSpec.scala b/src/test/scala/firrtlTests/transforms/InferWidthsWithAnnosSpec.scala new file mode 100644 index 00000000..54a3df40 --- /dev/null +++ b/src/test/scala/firrtlTests/transforms/InferWidthsWithAnnosSpec.scala @@ -0,0 +1,230 @@ +// See LICENSE for license details. + +package firrtlTests.transforms + +import firrtlTests.FirrtlFlatSpec +import org.scalatest._ +import org.scalatest.prop._ +import firrtl._ +import firrtl.passes._ +import firrtl.passes.wiring.{WiringTransform, SourceAnnotation, SinkAnnotation} +import firrtl.ir.Circuit +import firrtl.annotations._ +import firrtl.annotations.TargetToken.{Field, Index} + + +class InferWidthsWithAnnosSpec extends FirrtlFlatSpec { + private def executeTest(input: String, + check: String, + transforms: Seq[Transform], + annotations: Seq[Annotation]) = { + val start = CircuitState(parse(input), ChirrtlForm, annotations) + val end = transforms.foldLeft(start) { + (c: CircuitState, t: Transform) => t.runTransform(c) + } + val resLines = end.circuit.serialize.split("\n") map normalized + val checkLines = parse(check).serialize.split("\n") map normalized + + resLines should be (checkLines) + } + + "CheckWidths on wires with unknown widths" should "result in an error" in { + val transforms = Seq( + ToWorkingIR, + CheckHighForm, + ResolveKinds, + InferTypes, + CheckTypes, + ResolveGenders, + new InferWidths, + CheckWidths) + + val input = + """circuit Top : + | module Top : + | inst b of B + | inst a of A + | + | module B : + | wire x: UInt<3> + | + | module A : + | wire y: UInt""".stripMargin + + // A.y should have uninferred width + intercept[CheckWidths.UninferredWidth] { + executeTest(input, "", transforms, Seq.empty) + } + } + + "InferWidthsWithAnnos" should "infer widths using WidthGeqConstraintAnnotation" in { + val transforms = Seq( + ToWorkingIR, + CheckHighForm, + ResolveKinds, + InferTypes, + CheckTypes, + ResolveGenders, + new InferWidths, + CheckWidths) + + val annos = Seq(WidthGeqConstraintAnnotation( + ReferenceTarget("Top", "A", Nil, "y", Nil), + ReferenceTarget("Top", "B", Nil, "x", Nil))) + + val input = + """circuit Top : + | module Top : + | inst b of B + | inst a of A + | + | module B : + | wire x: UInt<3> + | + | module A : + | wire y: UInt""".stripMargin + + val output = + """circuit Top : + | module Top : + | inst b of B + | inst a of A + | + | module B : + | wire x: UInt<3> + | + | module A : + | wire y: UInt<3>""".stripMargin + + // A.y should have same width as B.x + executeTest(input, output, transforms, annos) + } + + "InferWidthsWithAnnos" should "work with token paths" in { + val transforms = Seq( + ToWorkingIR, + CheckHighForm, + ResolveKinds, + InferTypes, + CheckTypes, + ResolveGenders, + new InferWidths, + CheckWidths) + + val tokenLists = Seq( + Seq(Field("x")), + Seq(Field("y"), Index(0), Field("yy")), + Seq(Field("y"), Index(1), Field("yy")) + ) + + val annos = tokenLists.map { tokens => + WidthGeqConstraintAnnotation( + ReferenceTarget("Top", "A", Nil, "bundle", tokens), + ReferenceTarget("Top", "B", Nil, "bundle", tokens)) + } + + val input = + """circuit Top : + | module Top : + | inst b of B + | inst a of A + | + | module B : + | wire bundle : {x : UInt<1>, y: {yy : UInt<3>}[2] } + | + | module A : + | wire bundle : {x : UInt, y: {yy : UInt}[2] }""".stripMargin + + val output = + """circuit Top : + | module Top : + | inst b of B + | inst a of A + | + | module B : + | wire bundle : {x : UInt<1>, y: {yy : UInt<3>}[2] } + | + | module A : + | wire bundle : {x : UInt<1>, y: {yy : UInt<3>}[2] }""".stripMargin + + // elements of A.bundle should have same width as B.bundle + executeTest(input, output, transforms, annos) + } + + "InferWidthsWithAnnos" should "work with WiringTransform" in { + def transforms = Seq( + ToWorkingIR, + ResolveKinds, + InferTypes, + ResolveGenders, + new InferWidths, + CheckWidths, + new WiringTransform, + new ResolveAndCheck + ) + val sourceTarget = ComponentName("bundle", ModuleName("A", CircuitName("Top"))) + val source = SourceAnnotation(sourceTarget, "pin") + + val sinkTarget = ComponentName("bundle", ModuleName("B", CircuitName("Top"))) + val sink = SinkAnnotation(sinkTarget, "pin") + + val tokenLists = Seq( + Seq(Field("x")), + Seq(Field("y"), Index(0), Field("yy")), + Seq(Field("y"), Index(1), Field("yy")) + ) + + val wgeqAnnos = tokenLists.map { tokens => + WidthGeqConstraintAnnotation( + ReferenceTarget("Top", "A", Nil, "bundle", tokens), + ReferenceTarget("Top", "B", Nil, "bundle", tokens)) + } + + val failAnnos = Seq(source, sink) + val successAnnos = wgeqAnnos ++: failAnnos + + val input = + """circuit Top : + | module Top : + | inst b of B + | inst a of A + | + | module B : + | wire bundle : {x : UInt<1>, y: {yy : UInt<3>}[2] } + | + | module A : + | wire bundle : {x : UInt, y: {yy : UInt}[2] }""".stripMargin + + val output = + """circuit Top : + | module Top : + | wire bundle : {x : UInt<1>, y: {yy : UInt<3>}[2] } + | inst b of B + | inst a of A + | b.pin <= bundle + | bundle <= a.bundle_0 + | + | module B : + | input pin : {x : UInt<1>, y: {yy : UInt<3>}[2] } + | wire bundle : {x : UInt<1>, y: {yy : UInt<3>}[2] } + | bundle <= pin + | + | module A : + | output bundle_0 : {x : UInt<1>, y: {yy : UInt<3>}[2] } + | wire bundle : {x : UInt<1>, y: {yy : UInt<3>}[2] } + | bundle_0 <= bundle""" + .stripMargin + + // should fail without extra constraint annos due to UninferredWidths + val exceptions = intercept[PassExceptions] { + executeTest(input, "", transforms, failAnnos) + }.exceptions.reverse + + val msg = exceptions.head.toString + assert(msg.contains(s"2 errors detected!")) + assert(exceptions.tail.forall(_.isInstanceOf[CheckWidths.UninferredWidth])) + + // should pass with extra constraints + executeTest(input, output, transforms, successAnnos) + } +} |
