summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/scala/chisel3/experimental/verification/package.scala41
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/Converter.scala8
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala7
-rw-r--r--src/main/scala/chisel3/internal/firrtl/Emitter.scala2
-rw-r--r--src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala38
5 files changed, 96 insertions, 0 deletions
diff --git a/core/src/main/scala/chisel3/experimental/verification/package.scala b/core/src/main/scala/chisel3/experimental/verification/package.scala
new file mode 100644
index 00000000..a983a6fd
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/verification/package.scala
@@ -0,0 +1,41 @@
+// See LICENSE for license details.
+
+package chisel3.experimental
+
+import chisel3.{Bool, CompileOptions}
+import chisel3.internal.Builder
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl.{Formal, Verification}
+import chisel3.internal.sourceinfo.SourceInfo
+
+package object verification {
+ object assert {
+ def apply(predicate: Bool, msg: String = "")(
+ implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ val clock = Builder.forcedClock
+ pushCommand(Verification(Formal.Assert, sourceInfo, clock.ref,
+ predicate.ref, msg))
+ }
+ }
+
+ object assume {
+ def apply(predicate: Bool, msg: String = "")(
+ implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ val clock = Builder.forcedClock
+ pushCommand(Verification(Formal.Assume, sourceInfo, clock.ref,
+ predicate.ref, msg))
+ }
+ }
+
+ object cover {
+ def apply(predicate: Bool, msg: String = "")(
+ implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ val clock = Builder.forcedClock
+ pushCommand(Verification(Formal.Cover, sourceInfo, clock.ref,
+ predicate.ref, msg))
+ }
+ }
+}
diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
index 67d87a68..304ddec6 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
@@ -125,6 +125,14 @@ private[chisel3] object Converter {
val (fmt, args) = unpack(pable, ctx)
Some(fir.Print(convert(info), fir.StringLit(fmt),
args.map(a => convert(a, ctx)), convert(clock, ctx), firrtl.Utils.one))
+ case Verification(op, info, clk, pred, msg) =>
+ val firOp = op match {
+ case Formal.Assert => fir.Formal.Assert
+ case Formal.Assume => fir.Formal.Assume
+ case Formal.Cover => fir.Formal.Cover
+ }
+ Some(fir.Verification(firOp, convert(info), convert(clk, ctx),
+ convert(pred, ctx), firrtl.Utils.one, fir.StringLit(msg)))
case _ => None
}
diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
index 89bc4a63..44fdb833 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -735,6 +735,13 @@ case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Comm
case class Stop(sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Command
case class Port(id: Data, dir: SpecifiedDirection)
case class Printf(sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Command
+object Formal extends Enumeration {
+ val Assert = Value("assert")
+ val Assume = Value("assume")
+ val Cover = Value("cover")
+}
+case class Verification(op: Formal.Value, sourceInfo: SourceInfo, clock: Arg,
+ predicate: Arg, message: String) extends Command
abstract class Component extends Arg {
def id: BaseModule
def name: String
diff --git a/src/main/scala/chisel3/internal/firrtl/Emitter.scala b/src/main/scala/chisel3/internal/firrtl/Emitter.scala
index be8d8f2f..36ac8710 100644
--- a/src/main/scala/chisel3/internal/firrtl/Emitter.scala
+++ b/src/main/scala/chisel3/internal/firrtl/Emitter.scala
@@ -80,6 +80,8 @@ private class Emitter(circuit: Circuit) {
val printfArgs = Seq(e.clock.fullName(ctx), "UInt<1>(1)",
"\"" + printf.format(fmt) + "\"") ++ args
printfArgs mkString ("printf(", ", ", ")")
+ case e: Verification => s"${e.op}(${e.clock.fullName(ctx)}, ${e.predicate.fullName(ctx)}, " +
+ s"UInt<1>(1), " + "\"" + s"${printf.format(e.message)}" + "\")"
case e: DefInvalid => s"${e.arg.fullName(ctx)} is invalid"
case e: DefInstance => s"inst ${e.name} of ${e.id.name}"
case w: WhenBegin =>
diff --git a/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala b/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala
new file mode 100644
index 00000000..521c16a3
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala
@@ -0,0 +1,38 @@
+// See LICENSE for license details.
+
+package chiselTests.experimental.verification
+
+import chisel3._
+import chisel3.experimental.{verification => formal}
+import chisel3.stage.ChiselStage
+import chiselTests.ChiselPropSpec
+
+class VerificationModule extends Module {
+ val io = IO(new Bundle{
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ io.out := io.in
+ formal.cover(io.in === 3.U)
+ when (io.in === 3.U) {
+ formal.assume(io.in =/= 2.U)
+ formal.assert(io.out === io.in)
+ }
+}
+
+class VerificationSpec extends ChiselPropSpec {
+
+ def assertContains[T](s: Seq[T], x: T): Unit = {
+ val containsLine = s.map(_ == x).reduce(_ || _)
+ assert(containsLine, s"\n $x\nwas not found in`\n ${s.mkString("\n ")}``")
+ }
+
+ property("basic equality check should work") {
+ val stage = new ChiselStage
+ val fir = stage.emitFirrtl(new VerificationModule)
+ val lines = fir.split("\n").map(_.trim)
+ assertContains(lines, "cover(clock, _T, UInt<1>(\"h1\"), \"\") @[VerificationSpec.scala 16:15]")
+ assertContains(lines, "assume(clock, _T_2, UInt<1>(\"h1\"), \"\") @[VerificationSpec.scala 18:18]")
+ assertContains(lines, "assert(clock, _T_3, UInt<1>(\"h1\"), \"\") @[VerificationSpec.scala 19:18]")
+ }
+}