aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/passes/Legalize.scala18
-rw-r--r--src/test/resources/passes/Legalize/Legalize.fir22
-rw-r--r--src/test/scala/firrtl/testutils/FirrtlSpec.scala25
-rw-r--r--src/test/scala/firrtlTests/LegalizeSpec.scala4
-rw-r--r--src/test/scala/firrtlTests/NegSpec.scala46
5 files changed, 112 insertions, 3 deletions
diff --git a/src/main/scala/firrtl/passes/Legalize.scala b/src/main/scala/firrtl/passes/Legalize.scala
index ef0e1706..e1a39fbe 100644
--- a/src/main/scala/firrtl/passes/Legalize.scala
+++ b/src/main/scala/firrtl/passes/Legalize.scala
@@ -3,11 +3,11 @@
package firrtl.passes
import firrtl.PrimOps._
-import firrtl.Utils.{error, zero, BoolType}
+import firrtl.Utils.{error, getGroundZero, zero, BoolType}
import firrtl.ir._
import firrtl.options.Dependency
import firrtl.transforms.ConstantPropagation
-import firrtl.{bitWidth, Transform}
+import firrtl.{bitWidth, getWidth, Transform}
import firrtl.Mappers._
// Replace shr by amount >= arg width with 0 for UInts and MSB for SInts
@@ -56,6 +56,19 @@ object Legalize extends Pass {
SIntLiteral(value, IntWidth(expr.consts.head))
case _ => expr
}
+ // Convert `-x` to `0 - x`
+ private def legalizeNeg(expr: DoPrim): Expression = {
+ val arg = expr.args.head
+ arg.tpe match {
+ case tpe: SIntType =>
+ val zero = getGroundZero(tpe)
+ DoPrim(Sub, Seq(zero, arg), Nil, expr.tpe)
+ case tpe: UIntType =>
+ val zero = getGroundZero(tpe)
+ val sub = DoPrim(Sub, Seq(zero, arg), Nil, UIntType(tpe.width + IntWidth(1)))
+ DoPrim(AsSInt, Seq(sub), Nil, expr.tpe)
+ }
+ }
private def legalizeConnect(c: Connect): Statement = {
val t = c.loc.tpe
val w = bitWidth(t)
@@ -78,6 +91,7 @@ object Legalize extends Pass {
case Shr => legalizeShiftRight(prim)
case Pad => legalizePad(prim)
case Bits | Head | Tail => legalizeBitExtract(prim)
+ case Neg => legalizeNeg(prim)
case _ => prim
}
case e => e // respect pre-order traversal
diff --git a/src/test/resources/passes/Legalize/Legalize.fir b/src/test/resources/passes/Legalize/Legalize.fir
index 7e538695..a0a39845 100644
--- a/src/test/resources/passes/Legalize/Legalize.fir
+++ b/src/test/resources/passes/Legalize/Legalize.fir
@@ -39,3 +39,25 @@ circuit Legalize :
when neq(bar_15, UInt(1)) :
printf(clock, UInt(1), "Assertion failed!\n bar_15 != 0\n")
stop(clock, UInt(1), 1)
+
+ ; Check neg of literals
+ node negUInt0 = neg(UInt(123))
+ when neq(negUInt0, SInt(-123)) :
+ printf(clock, UInt(1), "Assertion failed!\n negUInt0 != -123\n")
+ stop(clock, UInt(1), 1)
+ node negUInt1 = neg(UInt<8>(0))
+ when neq(negUInt1, SInt<8>(0)) :
+ printf(clock, UInt(1), "Assertion failed!\n negUInt1 != 0\n")
+ stop(clock, UInt(1), 1)
+ node negSInt0 = neg(SInt(123))
+ when neq(negSInt0, SInt(-123)) :
+ printf(clock, UInt(1), "Assertion failed!\n negSInt0 != -123\n")
+ stop(clock, UInt(1), 1)
+ node negSInt1 = neg(SInt(-123))
+ when neq(negSInt1, SInt(123)) :
+ printf(clock, UInt(1), "Assertion failed!\n negSInt1 != 123\n")
+ stop(clock, UInt(1), 1)
+ node negSInt2 = neg(SInt(0))
+ when neq(negSInt2, SInt(0)) :
+ printf(clock, UInt(1), "Assertion failed!\n negSInt2 != 0\n")
+ stop(clock, UInt(1), 1)
diff --git a/src/test/scala/firrtl/testutils/FirrtlSpec.scala b/src/test/scala/firrtl/testutils/FirrtlSpec.scala
index 63def26a..4dc2d642 100644
--- a/src/test/scala/firrtl/testutils/FirrtlSpec.scala
+++ b/src/test/scala/firrtl/testutils/FirrtlSpec.scala
@@ -4,6 +4,7 @@ package firrtl.testutils
import java.io._
import java.security.Permission
+import scala.sys.process._
import logger.{LazyLogging, LogLevel, LogLevelAnnotation}
@@ -175,6 +176,22 @@ trait FirrtlRunners extends BackendCompilationUtilities {
compiler.compileAndEmit(CircuitState(circuit, HighForm, annotations), extraCheckTransforms)
}
+ /** Run Verilator lint on some Verilog text
+ *
+ * @param inputVerilog Verilog to pass to `verilator --lint-only`
+ * @return Verilator return 0
+ */
+ def lintVerilog(inputVerilog: String): Unit = {
+ val testDir = createTestDirectory(s"${this.getClass.getSimpleName}_lint")
+ val filename = new File(testDir, "test.v")
+ val w = new FileWriter(filename)
+ w.write(inputVerilog)
+ w.close()
+
+ val cmd = Seq("verilator", "--lint-only", filename.toString)
+ assert(cmd.!(loggingProcessLogger) == 0, "Lint must pass")
+ }
+
/** Compile a Firrtl file
*
* @param prefix is the name of the Firrtl file without path or file extension
@@ -413,6 +430,14 @@ abstract class ExecutionTest(
}
}
+/** Super class for execution driven Firrtl tests compiled without optimizations */
+abstract class ExecutionTestNoOpt(
+ name: String,
+ dir: String,
+ vFiles: Seq[String] = Seq.empty,
+ annotations: AnnotationSeq = Seq.empty)
+ extends ExecutionTest(name, dir, vFiles, RunFirrtlTransformAnnotation(new MinimumVerilogEmitter) +: annotations)
+
/** Super class for compilation driven Firrtl tests */
abstract class CompilationTest(name: String, dir: String) extends FirrtlPropSpec {
property(s"$name should compile correctly") {
diff --git a/src/test/scala/firrtlTests/LegalizeSpec.scala b/src/test/scala/firrtlTests/LegalizeSpec.scala
index 905d578e..ad85668e 100644
--- a/src/test/scala/firrtlTests/LegalizeSpec.scala
+++ b/src/test/scala/firrtlTests/LegalizeSpec.scala
@@ -2,6 +2,8 @@
package firrtlTests
-import firrtl.testutils.ExecutionTest
+import firrtl.testutils.{ExecutionTest, ExecutionTestNoOpt}
class LegalizeExecutionTest extends ExecutionTest("Legalize", "/passes/Legalize")
+// Legalize also needs to work when optimizations are turned off
+class LegalizeExecutionTestNoOpt extends ExecutionTestNoOpt("Legalize", "/passes/Legalize")
diff --git a/src/test/scala/firrtlTests/NegSpec.scala b/src/test/scala/firrtlTests/NegSpec.scala
new file mode 100644
index 00000000..c60294e3
--- /dev/null
+++ b/src/test/scala/firrtlTests/NegSpec.scala
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package firrtlTests
+
+import firrtl.testutils._
+
+class NegSpec extends FirrtlFlatSpec {
+ "unsigned neg" should "be correct and lint-clean" in {
+ val input =
+ """|circuit UnsignedNeg :
+ | module UnsignedNeg :
+ | input in : UInt<8>
+ | output out : SInt
+ | out <= neg(in)
+ |""".stripMargin
+ val expected =
+ """|module UnsignedNegRef(
+ | input [7:0] in,
+ | output [8:0] out
+ |);
+ | assign out = 8'd0 - in;
+ |endmodule""".stripMargin
+ firrtlEquivalenceWithVerilog(input, expected)
+ lintVerilog(compileToVerilog(input))
+ }
+
+ "signed neg" should "be correct and lint-clean" in {
+ val input =
+ """|circuit SignedNeg :
+ | module SignedNeg :
+ | input in : SInt<8>
+ | output out : SInt
+ | out <= neg(in)
+ |""".stripMargin
+ // -$signed(in) is a lint warning in Verilator but is functionally correct
+ val expected =
+ """|module SignedNegRef(
+ | input [7:0] in,
+ | output [8:0] out
+ |);
+ | assign out = -$signed(in);
+ |endmodule""".stripMargin
+ firrtlEquivalenceWithVerilog(input, expected)
+ lintVerilog(compileToVerilog(input))
+ }
+}