From 93621cd06d239b44b0c523add535788d096042d6 Mon Sep 17 00:00:00 2001 From: ducky Date: Thu, 17 Dec 2015 11:07:13 -0800 Subject: Add unit test for module deduplication --- .../scala/chiselTests/ParameterizedModule.scala | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/test/scala/chiselTests/ParameterizedModule.scala (limited to 'src') diff --git a/src/test/scala/chiselTests/ParameterizedModule.scala b/src/test/scala/chiselTests/ParameterizedModule.scala new file mode 100644 index 00000000..f356cebd --- /dev/null +++ b/src/test/scala/chiselTests/ParameterizedModule.scala @@ -0,0 +1,41 @@ +// See LICENSE for license details. + +package chiselTests + +import org.scalatest._ +import Chisel._ +import Chisel.testers.BasicTester + +class ParameterizedModule(invert: Boolean) extends Module { + val io = new Bundle { + val in = new Bool(INPUT) + val out = new Bool(OUTPUT) + } + if (invert) { + io.out := !io.in + } else { + io.out := io.in + } +} + +/** A simple test to check Module deduplication doesn't affect correctness (two + * modules with the same name but different contents aren't aliased). Doesn't + * check that deduplication actually happens, though. + */ +class ParameterizedModuleTester() extends BasicTester { + val invert = Module(new ParameterizedModule(true)) + val noninvert = Module(new ParameterizedModule(false)) + + invert.io.in := Bool(true) + noninvert.io.in := Bool(true) + assert(invert.io.out === Bool(false)) + assert(noninvert.io.out === Bool(true)) + + stop() +} + +class ParameterizedModuleSpec extends ChiselFlatSpec { + "Different parameterized modules" should "have different behavior" in { + assert(execute{ new ParameterizedModuleTester() }) + } +} -- cgit v1.2.3 From ccc88bbd9d462f04fe1dd39327349aeea8de9d3c Mon Sep 17 00:00:00 2001 From: ducky Date: Thu, 17 Dec 2015 17:41:05 -0800 Subject: Only deduplicate when Module classname is the same --- .../scala/Chisel/internal/firrtl/Emitter.scala | 64 ++++++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/main/scala/Chisel/internal/firrtl/Emitter.scala b/src/main/scala/Chisel/internal/firrtl/Emitter.scala index 8597454a..0c5da829 100644 --- a/src/main/scala/Chisel/internal/firrtl/Emitter.scala +++ b/src/main/scala/Chisel/internal/firrtl/Emitter.scala @@ -21,7 +21,7 @@ private class Emitter(circuit: Circuit) { case e: Stop => s"stop(${e.clk.fullName(ctx)}, UInt<1>(1), ${e.ret})" case e: Printf => s"""printf(${e.clk.fullName(ctx)}, UInt<1>(1), "${e.format}"${e.ids.map(_.fullName(ctx)).fold(""){_ + ", " + _}})""" case e: DefInstance => { - val modName = moduleMap.getOrElse(e.id.name, e.id.name) + val modName = moduleMap.get(e.id.name).get s"inst ${e.name} of $modName" } @@ -32,31 +32,59 @@ private class Emitter(circuit: Circuit) { unindent() "skip" } - private def emitBody(m: Component) = { - val me = new StringBuilder + + // Map of Module FIRRTL definition to FIRRTL name, if it has been emitted already. + private val defnMap = collection.mutable.HashMap[String, String]() + // Map of Component name to FIRRTL id. + private val moduleMap = collection.mutable.HashMap[String, String]() + + /** Generates the FIRRTL module definition with a specified name. + */ + private def moduleDefn(m: Component, name: String): String = { + val body = new StringBuilder + m.id match { + case _: BlackBox => body ++= newline + s"extmodule $name : " + case _: Module => body ++= newline + s"module $name : " + } withIndent { for (p <- m.ports) - me ++= newline + emitPort(p) - me ++= newline - for (cmd <- m.commands) - me ++= newline + emit(cmd, m) - me ++= newline + body ++= newline + emitPort(p) + body ++= newline + + m.id match { + case _: BlackBox => + // TODO: BlackBoxes should be empty, but funkiness in Module() means + // it's not for now. Eventually, this should assert out. + case _: Module => for (cmd <- m.commands) { + body ++= newline + emit(cmd, m) + } + } + body ++= newline } - me + body.toString() } - private val bodyMap = collection.mutable.HashMap[StringBuilder, String]() - private val moduleMap = collection.mutable.HashMap[String, String]() - + /** Returns the FIRRTL declaration and body of a module, or nothing if it's a + * duplicate of something already emitted (on the basis of simple string + * matching). + */ private def emit(m: Component): String = { - val body = emitBody(m) - bodyMap get body match { - case Some(name) => - moduleMap(m.name) = name + // Generate the body. + val moduleName = m.id.getClass.getName.split('.').last + val defn = moduleDefn(m, moduleName) + + defnMap get defn match { + case Some(deduplicatedName) => + moduleMap(m.name) = deduplicatedName "" case None => - bodyMap(body) = m.name - newline + s"module ${m.name} : " + body + require(!(moduleMap contains m.name), + "emitting module with same name but different contents") + + moduleMap(m.name) = m.name + defnMap(defn) = m.name + + moduleDefn(m, m.name) } } -- cgit v1.2.3