aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Lawson2017-01-20 08:52:15 -0800
committerGitHub2017-01-20 08:52:15 -0800
commit58c1840c7db278417fcceaf035e9df7601233406 (patch)
tree29c6c3e1d1ad26f06f72b45cfe4f2ead7f83aee9 /src
parentefc367e883ffd8c0a239f04943e4bda5ce356da4 (diff)
parent51fde13c21825f87ee7fc854eb41215e02076bb5 (diff)
Merge branch 'master' into scaladocroot
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/Emitter.scala1
-rw-r--r--src/main/scala/firrtl/ExecutionOptionsManager.scala8
-rw-r--r--src/main/scala/firrtl/LoweringCompilers.scala6
-rw-r--r--src/main/scala/firrtl/passes/VerilogModulusCleanup.scala84
-rw-r--r--src/test/scala/firrtlTests/CompilerTests.scala37
-rw-r--r--src/test/scala/firrtlTests/DriverSpec.scala1
-rw-r--r--src/test/scala/firrtlTests/MultiThreadingSpec.scala1
-rw-r--r--src/test/scala/firrtlTests/VerilogEmitterTests.scala21
8 files changed, 156 insertions, 3 deletions
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index e40a18a4..a290ced4 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -562,6 +562,7 @@ class VerilogEmitter extends Emitter with PassBased {
}
def passSeq = Seq(
+ passes.VerilogModulusCleanup,
passes.VerilogWrap,
passes.VerilogRename,
passes.VerilogPrep)
diff --git a/src/main/scala/firrtl/ExecutionOptionsManager.scala b/src/main/scala/firrtl/ExecutionOptionsManager.scala
index ab900a36..62ecb1c9 100644
--- a/src/main/scala/firrtl/ExecutionOptionsManager.scala
+++ b/src/main/scala/firrtl/ExecutionOptionsManager.scala
@@ -161,6 +161,7 @@ case class FirrtlExecutionOptions(
compilerName match {
case "high" => new HighFirrtlCompiler()
case "low" => new LowFirrtlCompiler()
+ case "middle" => new MiddleFirrtlCompiler()
case "verilog" => new VerilogCompiler()
}
}
@@ -170,6 +171,7 @@ case class FirrtlExecutionOptions(
case "verilog" => "v"
case "low" => "lo.fir"
case "high" => "hi.fir"
+ case "middle" => "mid.fir"
case _ =>
throw new Exception(s"Illegal compiler name $compilerName")
}
@@ -247,12 +249,12 @@ trait HasFirrtlOptions {
parser.opt[String]("compiler")
.abbr("X")
- .valueName ("<high|low|verilog>")
+ .valueName ("<high|middle|low|verilog>")
.foreach { x =>
firrtlOptions = firrtlOptions.copy(compilerName = x)
}
.validate { x =>
- if (Array("high", "low", "verilog").contains(x.toLowerCase)) parser.success
+ if (Array("high", "middle", "low", "verilog").contains(x.toLowerCase)) parser.success
else parser.failure(s"$x not a legal compiler")
}.text {
s"compiler to use, default is ${firrtlOptions.compilerName}"
@@ -342,7 +344,7 @@ sealed trait FirrtlExecutionResult
* Indicates a successful execution of the firrtl compiler, returning the compiled result and
* the type of compile
*
- * @param emitType The name of the compiler used, currently "high", "low", or "verilog"
+ * @param emitType The name of the compiler used, currently "high", "middle", "low", or "verilog"
* @param emitted The text result of the compilation, could be verilog or firrtl text.
*/
case class FirrtlExecutionSuccess(emitType: String, emitted: String) extends FirrtlExecutionResult
diff --git a/src/main/scala/firrtl/LoweringCompilers.scala b/src/main/scala/firrtl/LoweringCompilers.scala
index c29ce01a..44d3a757 100644
--- a/src/main/scala/firrtl/LoweringCompilers.scala
+++ b/src/main/scala/firrtl/LoweringCompilers.scala
@@ -119,6 +119,12 @@ class HighFirrtlCompiler extends Compiler {
def transforms: Seq[Transform] = getLoweringTransforms(ChirrtlForm, HighForm)
}
+/** Emits middle Firrtl input circuit */
+class MiddleFirrtlCompiler extends Compiler {
+ def emitter = new FirrtlEmitter
+ def transforms: Seq[Transform] = getLoweringTransforms(ChirrtlForm, MidForm)
+}
+
/** Emits lowered input circuit */
class LowFirrtlCompiler extends Compiler {
def emitter = new FirrtlEmitter
diff --git a/src/main/scala/firrtl/passes/VerilogModulusCleanup.scala b/src/main/scala/firrtl/passes/VerilogModulusCleanup.scala
new file mode 100644
index 00000000..b4df534f
--- /dev/null
+++ b/src/main/scala/firrtl/passes/VerilogModulusCleanup.scala
@@ -0,0 +1,84 @@
+// See LICENSE for license details.
+
+package firrtl
+package passes
+
+import firrtl.ir._
+import firrtl.Mappers._
+import firrtl.PrimOps.{Bits, Rem}
+import firrtl.Utils._
+
+import scala.collection.mutable
+
+/**
+ * Verilog has the width of (a % b) = Max(W(a), W(b))
+ * FIRRTL has the width of (a % b) = Min(W(a), W(b)), which makes more sense,
+ * but nevertheless is a problem when emitting verilog
+ *
+ * This pass finds every instance of (a % b) and:
+ * 1) adds a temporary node equal to (a % b) with width Max(W(a), W(b))
+ * 2) replaces the reference to (a % b) with a bitslice of the temporary node
+ * to get back down to width Min(W(a), W(b))
+ *
+ * This is technically incorrect firrtl, but allows the verilog emitter
+ * to emit correct verilog without needing to add temporary nodes
+ */
+object VerilogModulusCleanup extends Pass {
+ def name = "Add temporary nodes with verilog widths for modulus"
+
+ private def onModule(m: Module): Module = {
+ val namespace = Namespace(m)
+ def onStmt(s: Statement): Statement = {
+ val v = mutable.ArrayBuffer[Statement]()
+
+ def getWidth(e: Expression): Width = e.tpe match {
+ case t: GroundType => t.width
+ case t => UnknownWidth
+ }
+
+ def maxWidth(ws: Seq[Width]): Width = ws reduceLeft { (x,y) => (x,y) match {
+ case (IntWidth(x), IntWidth(y)) => IntWidth(x max y)
+ case (x, y) => UnknownWidth
+ }}
+
+ def verilogRemWidth(e: DoPrim)(tpe: Type): Type = {
+ val newWidth = maxWidth(e.args.map(exp => getWidth(exp)))
+ tpe mapWidth (w => newWidth)
+ }
+
+ def removeRem(e: Expression): Expression = e match {
+ case e: DoPrim => e.op match {
+ case Rem =>
+ val name = namespace.newTemp
+ val newType = e mapType verilogRemWidth(e)
+ v += DefNode(get_info(s), name, e mapType verilogRemWidth(e))
+ val remRef = WRef(name, newType.tpe, kind(e), gender(e))
+ val remWidth = bitWidth(e.tpe)
+ DoPrim(Bits, Seq(remRef), Seq(remWidth - 1, BigInt(0)), e.tpe)
+ case _ => e
+ }
+ case _ => e
+ }
+
+ s map removeRem match {
+ case x: Block => x map onStmt
+ case EmptyStmt => EmptyStmt
+ case x =>
+ v += x
+ v.size match {
+ case 1 => v.head
+ case _ => Block(v.toSeq)
+ }
+ }
+ }
+ Module(m.info, m.name, m.ports, onStmt(m.body))
+ }
+
+ def run(c: Circuit): Circuit = {
+ val modules = c.modules map {
+ case m: Module => onModule(m)
+ case m: ExtModule => m
+ }
+ Circuit(c.info, modules, c.main)
+ }
+}
diff --git a/src/test/scala/firrtlTests/CompilerTests.scala b/src/test/scala/firrtlTests/CompilerTests.scala
index 2a5311f8..a9fce0c2 100644
--- a/src/test/scala/firrtlTests/CompilerTests.scala
+++ b/src/test/scala/firrtlTests/CompilerTests.scala
@@ -14,6 +14,7 @@ import firrtl.{
CircuitState,
Compiler,
HighFirrtlCompiler,
+ MiddleFirrtlCompiler,
LowFirrtlCompiler,
Parser,
VerilogCompiler
@@ -61,6 +62,42 @@ class HighFirrtlCompilerSpec extends CompilerSpec with Matchers {
}
/**
+ * An example test for testing the MiddleFirrtlCompiler.
+ *
+ * Given an input Firrtl circuit (expressed as a string),
+ * the compiler is executed. The output of the compiler is
+ * a lowered (to MidForm) version of the input circuit. The output is
+ * string compared to the correct lowered circuit.
+ */
+class MiddleFirrtlCompilerSpec extends CompilerSpec with Matchers {
+ val compiler = new MiddleFirrtlCompiler()
+ val input =
+ """
+circuit Top :
+ module Top :
+ input reset : UInt<1>
+ input a : UInt<1>[2]
+ wire b : UInt
+ b <= a[0]
+ when reset :
+ b <= UInt(0)
+"""
+ // Verify that Vecs are retained, but widths are inferred and whens are expanded.
+ val check = Seq(
+ "circuit Top :",
+ " module Top :",
+ " input reset : UInt<1>",
+ " input a : UInt<1>[2]",
+ " wire b : UInt<1>",
+ " node _GEN_0 = mux(reset, UInt<1>(\"h0\"), a[0])",
+ " b <= _GEN_0\n\n"
+ ).reduce(_ + "\n" + _)
+ "A circuit" should "match exactly to its MidForm state" in {
+ (parse(getOutput)) should be (parse(check))
+ }
+}
+
+/**
* An example test for testing the LoweringCompiler.
*
* Given an input Firrtl circuit (expressed as a string),
diff --git a/src/test/scala/firrtlTests/DriverSpec.scala b/src/test/scala/firrtlTests/DriverSpec.scala
index 26b32baa..9f29b918 100644
--- a/src/test/scala/firrtlTests/DriverSpec.scala
+++ b/src/test/scala/firrtlTests/DriverSpec.scala
@@ -156,6 +156,7 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
Seq(
"low" -> "./Dummy.lo.fir",
"high" -> "./Dummy.hi.fir",
+ "middle" -> "./Dummy.mid.fir",
"verilog" -> "./Dummy.v"
).foreach { case (compilerName, expectedOutputFileName) =>
val manager = new ExecutionOptionsManager("test") with HasFirrtlOptions {
diff --git a/src/test/scala/firrtlTests/MultiThreadingSpec.scala b/src/test/scala/firrtlTests/MultiThreadingSpec.scala
index 169aa6b2..1698c462 100644
--- a/src/test/scala/firrtlTests/MultiThreadingSpec.scala
+++ b/src/test/scala/firrtlTests/MultiThreadingSpec.scala
@@ -21,6 +21,7 @@ class MultiThreadingSpec extends FirrtlPropSpec {
// The parameters we're testing with
val compilers = Seq(
new firrtl.HighFirrtlCompiler,
+ new firrtl.MiddleFirrtlCompiler,
new firrtl.LowFirrtlCompiler,
new firrtl.VerilogCompiler)
val inputFilePath = s"/integration/GCDTester.fir" // arbitrary
diff --git a/src/test/scala/firrtlTests/VerilogEmitterTests.scala b/src/test/scala/firrtlTests/VerilogEmitterTests.scala
index 39592269..41fd6e41 100644
--- a/src/test/scala/firrtlTests/VerilogEmitterTests.scala
+++ b/src/test/scala/firrtlTests/VerilogEmitterTests.scala
@@ -74,4 +74,25 @@ class DoPrimVerilog extends FirrtlFlatSpec {
|""".stripMargin.split("\n") map normalized
executeTest(input, check, compiler)
}
+ "Rem" should "emit correctly" in {
+ val compiler = new VerilogCompiler
+ val input =
+ """circuit Test :
+ | module Test :
+ | input in : UInt<8>
+ | output out : UInt<1>
+ | out <= rem(in, UInt<1>("h1"))
+ |""".stripMargin
+ val check =
+ """module Test(
+ | input [7:0] in,
+ | output out
+ |);
+ | wire [7:0] _GEN_0;
+ | assign out = _GEN_0[0];
+ | assign _GEN_0 = in % 8'h1;
+ |endmodule
+ |""".stripMargin.split("\n") map normalized
+ executeTest(input, check, compiler)
+ }
}