diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/firrtl/passes/Legalize.scala | 18 | ||||
| -rw-r--r-- | src/test/resources/passes/Legalize/Legalize.fir | 22 | ||||
| -rw-r--r-- | src/test/scala/firrtl/testutils/FirrtlSpec.scala | 25 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/LegalizeSpec.scala | 4 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/NegSpec.scala | 46 |
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)) + } +} |
