aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Izraelevitz2020-03-06 18:03:55 -0800
committerGitHub2020-03-07 02:03:55 +0000
commitdd72b24dde5b28aef4a3728fdb770e26f5dbc54d (patch)
tree908ab02e878509a1734562851baa82732cfa8d18
parent140a29a851a9e5b0b1cd486cc5ba53c3ff763f27 (diff)
Add firrtl-json serializers (#1430)
* Add firrtl-json serializers * Added support for ports, info. Added docs and tests
-rw-r--r--src/main/scala/firrtl/Parser.scala122
-rw-r--r--src/main/scala/firrtl/annotations/JsonProtocol.scala36
-rw-r--r--src/test/scala/firrtlTests/annotationTests/JsonProtocolSpec.scala42
3 files changed, 199 insertions, 1 deletions
diff --git a/src/main/scala/firrtl/Parser.scala b/src/main/scala/firrtl/Parser.scala
index ddc858e4..0388c453 100644
--- a/src/main/scala/firrtl/Parser.scala
+++ b/src/main/scala/firrtl/Parser.scala
@@ -63,8 +63,130 @@ object Parser extends LazyLogging {
def parse(lines: Seq[String]): Circuit = parseString(lines.mkString("\n"), UseInfo)
+
+ /** Parse the concrete syntax of a FIRRTL [[firrtl.ir.Circuit]], e.g.
+ * {{{
+ * """circuit Top:
+ * | module Top:
+ * | input x: UInt
+ * | node y = x
+ * |""".stripMargin
+ * }}}
+ * becomes:
+ * {{{
+ * Circuit(
+ * NoInfo,
+ * Seq(Module(
+ * NoInfo,
+ * "Top",
+ * Seq(Port(NoInfo, "x", Input, UIntType(UnknownWidth))),
+ * Block(DefNode(NoInfo, "y", Ref("x", UnknownType)))
+ * )),
+ * "Top"
+ * )
+ * }}}
+ * @param text concrete Circuit syntax
+ * @return
+ */
def parse(text: String): Circuit = parseString(text, UseInfo)
+ /** Parse the concrete syntax of a FIRRTL [[firrtl.ir.Type]], e.g.
+ * "UInt<3>" becomes:
+ * {{{
+ * UIntType(IntWidth(BigInt(3)))
+ * }}}
+ * @param tpe concrete Type syntax
+ * @return
+ */
+ def parseType(tpe: String): Type = {
+ val input = Seq("circuit Top:\n", " module Top:\n", s" input x:$tpe\n")
+ val circuit = parse(input)
+ circuit.modules.head.ports.head.tpe
+ }
+
+ /** Parse the concrete syntax of a FIRRTL [[firrtl.ir.Expression]], e.g.
+ * "add(x, y)" becomes:
+ * {{{
+ * DoPrim(Add, Seq(Ref("x", UnknownType), Ref("y", UnknownType), Nil, UnknownType)
+ * }}}
+ * @param expr concrete Expression syntax
+ * @return
+ */
+ def parseExpression(expr: String): Expression = {
+ val input = Seq("circuit Top:\n", " module Top:\n", s" node x = $expr\n")
+ val circuit = parse(input)
+ circuit.modules match {
+ case Seq(Module(_, _, _, Block(Seq(DefNode(_, _, value))))) => value
+ }
+ }
+
+ /** Parse the concrete syntax of a FIRRTL [[firrtl.ir.Statement]], e.g.
+ * "wire x: UInt" becomes:
+ * {{{
+ * DefWire(NoInfo, "x", UIntType(UnknownWidth))
+ * }}}
+ * @param statement concrete Statement syntax
+ * @return
+ */
+ def parseStatement(statement: String): Statement = {
+ val input = Seq("circuit Top:\n", " module Top:\n") ++ statement.split("\n").map(" " + _)
+ val circuit = parse(input)
+ circuit.modules.head.asInstanceOf[Module].body
+ }
+
+ /** Parse the concrete syntax of a FIRRTL [[firrtl.ir.Port]], e.g.
+ * "input x: UInt" becomes:
+ * {{{
+ * Port(NoInfo, "x", Input, UIntType(UnknownWidth))
+ * }}}
+ * @param port concrete Port syntax
+ * @return
+ */
+ def parsePort(port: String): Port = {
+ val input = Seq("circuit Top:\n", " module Top:\n", s" $port\n")
+ val circuit = parse(input)
+ circuit.modules.head.ports.head
+ }
+
+ /** Parse the concrete syntax of a FIRRTL [[firrtl.ir.DefModule]], e.g.
+ * {{{
+ * """module Top:
+ * | input x: UInt
+ * | node y = x
+ * |""".stripMargin
+ * }}}
+ * becomes:
+ * {{{
+ * Module(
+ * NoInfo,
+ * "Top",
+ * Seq(Port(NoInfo, "x", Input, UIntType(UnknownWidth))),
+ * Block(DefNode(NoInfo, "y", Ref("x", UnknownType)))
+ * )
+ * }}}
+ * @param module concrete DefModule syntax
+ * @return
+ */
+ def parseDefModule(module: String): DefModule = {
+ val input = Seq("circuit Top:\n") ++ module.split("\n").map(" " + _)
+ val circuit = parse(input)
+ circuit.modules.head
+ }
+
+ /** Parse the concrete syntax of a FIRRTL [[firrtl.ir.Info]], e.g.
+ * "@[FPU.scala 509:25]" becomes:
+ * {{{
+ * FileInfo("FPU.scala 509:25")
+ * }}}
+ * @param info concrete Info syntax
+ * @return
+ */
+ def parseInfo(info: String): Info = {
+ val input = Seq(s"circuit Top: $info\n", " module Top:\n", " input x: UInt\n")
+ val circuit = parse(input)
+ circuit.info
+ }
+
sealed abstract class InfoMode
case object IgnoreInfo extends InfoMode
diff --git a/src/main/scala/firrtl/annotations/JsonProtocol.scala b/src/main/scala/firrtl/annotations/JsonProtocol.scala
index 55043b63..312b826a 100644
--- a/src/main/scala/firrtl/annotations/JsonProtocol.scala
+++ b/src/main/scala/firrtl/annotations/JsonProtocol.scala
@@ -1,7 +1,10 @@
+// See LICENSE for license details.
package firrtl
package annotations
+import firrtl.ir._
+
import scala.util.{Try, Failure}
import org.json4s._
@@ -90,6 +93,35 @@ object JsonProtocol {
{ case JString(s) => Target.deserialize(s).asInstanceOf[CompleteTarget] },
{ case named: CompleteTarget => JString(named.serialize) }
))
+ // FIRRTL Serializers
+ class TypeSerializer extends CustomSerializer[Type](format => (
+ { case JString(s) => Parser.parseType(s) },
+ { case tpe: Type => JString(tpe.serialize) }
+ ))
+ class ExpressionSerializer extends CustomSerializer[Expression](format => (
+ { case JString(s) => Parser.parseExpression(s) },
+ { case expr: Expression => JString(expr.serialize) }
+ ))
+ class StatementSerializer extends CustomSerializer[Statement](format => (
+ { case JString(s) => Parser.parseStatement(s) },
+ { case statement: Statement => JString(statement.serialize) }
+ ))
+ class PortSerializer extends CustomSerializer[Port](format => (
+ { case JString(s) => Parser.parsePort(s) },
+ { case port: Port => JString(port.serialize) }
+ ))
+ class DefModuleSerializer extends CustomSerializer[DefModule](format => (
+ { case JString(s) => Parser.parseDefModule(s) },
+ { case mod: DefModule => JString(mod.serialize) }
+ ))
+ class CircuitSerializer extends CustomSerializer[Circuit](format => (
+ { case JString(s) => Parser.parse(s) },
+ { case cir: Circuit => JString(cir.serialize) }
+ ))
+ class InfoSerializer extends CustomSerializer[Info](format => (
+ { case JString(s) => Parser.parseInfo(s) },
+ { case info: Info => JString(info.serialize) }
+ ))
/** Construct Json formatter for annotations */
def jsonFormat(tags: Seq[Class[_]]) = {
@@ -99,7 +131,9 @@ object JsonProtocol {
new GenericTargetSerializer + new CircuitTargetSerializer + new ModuleTargetSerializer +
new InstanceTargetSerializer + new ReferenceTargetSerializer + new TransformSerializer +
new LoadMemoryFileTypeSerializer + new IsModuleSerializer + new IsMemberSerializer +
- new CompleteTargetSerializer
+ new CompleteTargetSerializer + new TypeSerializer + new ExpressionSerializer +
+ new StatementSerializer + new PortSerializer + new DefModuleSerializer +
+ new CircuitSerializer + new InfoSerializer
}
/** Serialize annotations to a String for emission */
diff --git a/src/test/scala/firrtlTests/annotationTests/JsonProtocolSpec.scala b/src/test/scala/firrtlTests/annotationTests/JsonProtocolSpec.scala
new file mode 100644
index 00000000..2dce89db
--- /dev/null
+++ b/src/test/scala/firrtlTests/annotationTests/JsonProtocolSpec.scala
@@ -0,0 +1,42 @@
+// See LICENSE for license details.
+
+package firrtlTests.annotationTests
+
+import firrtl.Parser
+import firrtl.annotations.{Annotation, JsonProtocol, NoTargetAnnotation}
+import firrtl.ir._
+import org.scalatest.{FlatSpec, Matchers, PropSpec}
+
+case class AnAnnotation(
+ info: Info,
+ cir: Circuit,
+ mod: DefModule,
+ port: Port,
+ statement: Statement,
+ expr: Expression,
+ tpe: Type
+) extends NoTargetAnnotation
+
+class JsonProtocolSpec extends FlatSpec with Matchers {
+ "JsonProtocol" should "serialize and deserialize FIRRTL types" in {
+
+ val circuit =
+ """circuit Top: @[FPU.scala 509:25]
+ | module Top:
+ | input x: UInt
+ | output y: UInt
+ | y <= add(x, x)
+ |""".stripMargin
+ val cir = Parser.parse(circuit)
+ val mod = cir.modules.head
+ val port = mod.ports.head
+ val stmt = mod.asInstanceOf[Module].body
+ val expr = stmt.asInstanceOf[Block].stmts.head.asInstanceOf[Connect].expr
+ val tpe = port.tpe
+ val inputAnnos = Seq(AnAnnotation(cir.info, cir, mod, port, stmt, expr, tpe))
+ val annosString = JsonProtocol.serialize(inputAnnos)
+ val outputAnnos = JsonProtocol.deserialize(annosString)
+ inputAnnos should be (outputAnnos)
+ }
+
+}