// SPDX-License-Identifier: Apache-2.0 package firrtlTests import firrtl.annotations.{Annotation, CircuitName, ComponentName, ModuleName} import firrtl.transforms.{Flatten, FlattenAnnotation, NoCircuitDedupAnnotation} import firrtl.testutils._ /** * Tests deep inline transformation */ class FlattenTests extends LowTransformSpec { def transform = new Flatten def flatten(mod: String): Annotation = { val parts = mod.split('.') val modName = ModuleName(parts.head, CircuitName("Top")) // If this fails, bad input val name = if (parts.size == 1) modName else ComponentName(parts.tail.mkString("."), modName) FlattenAnnotation(name) } "The modules inside Top " should "be inlined" in { val input = """circuit Top : | module Top : | input a : UInt<32> | output b : UInt<32> | inst i of Inline1 | i.a <= a | b <= i.b | module Inline1 : | input a : UInt<32> | output b : UInt<32> | b <= a""".stripMargin val check = """circuit Top : | module Top : | input a : UInt<32> | output b : UInt<32> | wire i_a : UInt<32> | wire i_b : UInt<32> | i_b <= i_a | b <= i_b | i_a <= a | module Inline1 : | input a : UInt<32> | output b : UInt<32> | b <= a""".stripMargin execute(input, check, Seq(flatten("Top"))) } "Two instances of the same module inside Top " should "be inlined" in { val input = """circuit Top : | module Top : | input a : UInt<32> | output b : UInt<32> | inst i1 of Inline1 | inst i2 of Inline1 | i1.a <= a | node tmp = i1.b | i2.a <= tmp | b <= i2.b | module Inline1 : | input a : UInt<32> | output b : UInt<32> | b <= a""".stripMargin val check = """circuit Top : | module Top : | input a : UInt<32> | output b : UInt<32> | wire i1_a : UInt<32> | wire i1_b : UInt<32> | i1_b <= i1_a | wire i2_a : UInt<32> | wire i2_b : UInt<32> | i2_b <= i2_a | node tmp = i1_b | b <= i2_b | i1_a <= a | i2_a <= tmp | module Inline1 : | input a : UInt<32> | output b : UInt<32> | b <= a""".stripMargin execute(input, check, Seq(flatten("Top"))) } "The module instance i in Top " should "be inlined" in { val input = """circuit Top : | module Top : | input a : UInt<32> | input na : UInt<32> | output b : UInt<32> | output nb : UInt<32> | inst i of Inline1 | inst ni of NotInline1 | i.a <= a | b <= i.b | ni.a <= na | nb <= ni.b | module NotInline1 : | input a : UInt<32> | output b : UInt<32> | inst i of Inline2 | i.a <= a | b <= i.a | module Inline1 : | input a : UInt<32> | output b : UInt<32> | inst i of Inline2 | i.a <= a | b <= i.a | module Inline2 : | input a : UInt<32> | output b : UInt<32> | b <= a""".stripMargin val check = """circuit Top : | module Top : | input a : UInt<32> | input na : UInt<32> | output b : UInt<32> | output nb : UInt<32> | wire i_a : UInt<32> | wire i_b : UInt<32> | wire i_i_a : UInt<32> | wire i_i_b : UInt<32> | i_i_b <= i_i_a | i_b <= i_i_a | i_i_a <= i_a | inst ni of NotInline1 | b <= i_b | nb <= ni.b | i_a <= a | ni.a <= na | module NotInline1 : | input a : UInt<32> | output b : UInt<32> | inst i of Inline2 | b <= i.a | i.a <= a | module Inline1 : | input a : UInt<32> | output b : UInt<32> | inst i of Inline2 | b <= i.a | i.a <= a | module Inline2 : | input a : UInt<32> | output b : UInt<32> | b <= a""".stripMargin execute(input, check, Seq(flatten("Top.i"), NoCircuitDedupAnnotation)) } "The module Inline1" should "be inlined" in { val input = """circuit Top : | module Top : | input a : UInt<32> | input na : UInt<32> | output b : UInt<32> | output nb : UInt<32> | inst i of Inline1 | inst ni of NotInline1 | i.a <= a | b <= i.b | ni.a <= na | nb <= ni.b | module NotInline1 : | input a : UInt<32> | output b : UInt<32> | inst i of Inline2 | i.a <= a | b <= i.a | module Inline1 : | input a : UInt<32> | output b : UInt<32> | inst i of Inline2 | i.a <= a | b <= i.a | module Inline2 : | input a : UInt<32> | output b : UInt<32> | b <= a""".stripMargin val check = """circuit Top : | module Top : | input a : UInt<32> | input na : UInt<32> | output b : UInt<32> | output nb : UInt<32> | inst i of Inline1 | inst ni of NotInline1 | b <= i.b | nb <= ni.b | i.a <= a | ni.a <= na | module NotInline1 : | input a : UInt<32> | output b : UInt<32> | inst i of Inline2 | b <= i.a | i.a <= a | module Inline1 : | input a : UInt<32> | output b : UInt<32> | wire i_a : UInt<32> | wire i_b : UInt<32> | i_b <= i_a | b <= i_a | i_a <= a | module Inline2 : | input a : UInt<32> | output b : UInt<32> | b <= a""".stripMargin execute(input, check, Seq(flatten("Inline1"), NoCircuitDedupAnnotation)) } "The Flatten transform" should "do nothing if no flatten annotations are present" in { val input = """|circuit Foo: | module Foo: | input a: UInt<1> | output b: UInt<1> | b <= a |""".stripMargin execute(input, input, Seq.empty) } "The Flatten transform" should "ignore extmodules" in { val input = """ |circuit Top : | module Top : | input a : UInt<32> | output b : UInt<32> | inst i of Inline | i.a <= a | b <= i.b | module Inline : | input a : UInt<32> | output b : UInt<32> | inst i of ExternalMod | i.a <= a | b <= i.b | extmodule ExternalMod : | input a : UInt<32> | output b : UInt<32> | defname = ExternalMod """.stripMargin val check = """ |circuit Top : | module Top : | input a : UInt<32> | output b : UInt<32> | wire i_a : UInt<32> | wire i_b : UInt<32> | inst i_i of ExternalMod | i_b <= i_i.b | i_i.a <= i_a | b <= i_b | i_a <= a | module Inline : | input a : UInt<32> | output b : UInt<32> | inst i of ExternalMod | b <= i.b | i.a <= a | extmodule ExternalMod : | input a : UInt<32> | output b : UInt<32> | defname = ExternalMod """.stripMargin execute(input, check, Seq(flatten("Top"))) } "The Flatten transform" should "work on modules with no instances" in { val input = """ |circuit Top : | module Top : | input a : UInt<32> | output b : UInt<32> | b <= a """.stripMargin val check = input execute(input, check, Seq(flatten("Top"))) } }