Skip to content

Commit

Permalink
FIRRTL version support (#2543)
Browse files Browse the repository at this point in the history
* Parse version and hardcode emitted version

* Throw error if version is too high

* Parse version even if rest is invalid

* Change pattern match to if statement

* Improve version grammar

* Update tests

* Remove outdated comment

* Simplify grammar and use version class

* Simplify and add no version test

* Fix for conflicting lexer rule
  • Loading branch information
zyedidia authored Aug 26, 2022
1 parent a6851b8 commit 19fe90b
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 2 deletions.
11 changes: 10 additions & 1 deletion src/main/antlr4/FIRRTL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,16 @@ import firrtl.LexerHelper;

// Does there have to be at least one module?
circuit
: 'circuit' id ':' info? INDENT module* DEDENT EOF
: version? NEWLINE* 'circuit' id ':' info? INDENT module* DEDENT EOF
;

version
: 'FIRRTL' 'version' semver NEWLINE
;

// Due to lexer problems, something like 1.1.0 is lexed as DoubleLit '.' UnsignedInt
semver
: DoubleLit '.' UnsignedInt
;

module
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/firrtl/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ case class ParameterRedefinedException(message: String) extends ParserException(
case class InvalidStringLitException(message: String) extends ParserException(message)
case class InvalidEscapeCharException(message: String) extends ParserException(message)
case class SyntaxErrorsException(message: String) extends ParserException(message)
case class UnsupportedVersionException(message: String) extends ParserException(message)

object Parser extends LazyLogging {

Expand Down
10 changes: 10 additions & 0 deletions src/main/scala/firrtl/ir/Serializer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@ import firrtl.Utils
import firrtl.backends.experimental.smt.random.DefRandom
import firrtl.constraint.Constraint

case class Version(major: Int, minor: Int, patch: Int) {
def serialize: String = s"$major.$minor.$patch"
def incompatible(that: Version): Boolean =
this.major > that.major || (this.major == that.major && this.minor > that.minor)
}

object Serializer {
val NewLine = '\n'
val Indent = " "

// The version supported by the serializer.
val version = Version(1, 1, 0)

/** Converts a `FirrtlNode` into its string representation with
* default indentation.
*/
Expand Down Expand Up @@ -254,6 +263,7 @@ object Serializer {

private def s(node: Circuit)(implicit b: StringBuilder, indent: Int): Unit = node match {
case Circuit(info, modules, main) =>
b ++= s"FIRRTL version ${version.serialize}\n"
b ++= "circuit "; b ++= main; b ++= " :"; s(info)
if (modules.nonEmpty) {
newLineNoIndent(); s(modules.head)(b, indent + 1)
Expand Down
11 changes: 11 additions & 0 deletions src/main/scala/firrtl/parser/Listener.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import firrtl.antlr.{FIRRTLParser, _}
import firrtl.Visitor
import firrtl.Parser.InfoMode
import firrtl.ir._
import firrtl.UnsupportedVersionException

import scala.collection.mutable
import scala.concurrent.{Await, Future}
Expand All @@ -25,6 +26,16 @@ private[firrtl] class Listener(infoMode: InfoMode) extends FIRRTLBaseListener {
}

override def exitCircuit(ctx: FIRRTLParser.CircuitContext): Unit = {
if (ctx.version != null) {
val version = ctx.version.semver.getText
val parts = version.split("\\.")
val (major, minor, patch) = (parts(0).toInt, parts(1).toInt, parts(2).toInt)
if (Version(major, minor, patch).incompatible(Serializer.version)) {
throw new UnsupportedVersionException(
s"FIRRTL version ${version} is not supported (greater than ${Serializer.version.serialize})"
)
}
}
info = Some(visitor.visitInfo(Option(ctx.info), ctx))
main = Some(ctx.id.getText)
ctx.children = null // Null out to save memory
Expand Down
61 changes: 61 additions & 0 deletions src/test/scala/firrtlTests/ParserSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,67 @@ class ParserSpec extends FirrtlFlatSpec {
) ++ PrimOps.listing
}

// ********** FIRRTL version number **********
"Version 1.1.0" should "be accepted" in {
val input = """
|FIRRTL version 1.1.0
|circuit Test :
| module Test :
| input in : UInt<1>
| in <= UInt(0)
""".stripMargin
val c = firrtl.Parser.parse(input)
firrtl.Parser.parse(c.serialize)
}

"Version 1.1.1" should "be accepted" in {
val input = """
|FIRRTL version 1.1.1
|circuit Test :
| module Test :
| input in : UInt<1>
| in <= UInt(0)
""".stripMargin
val c = firrtl.Parser.parse(input)
firrtl.Parser.parse(c.serialize)
}

"No version" should "be accepted" in {
val input = """
|circuit Test :
| module Test :
| input in : { 0 : { 0 : { 0 : UInt<32>, flip 1 : UInt<32> } } }
| in.0.0.1 <= in.0.0.0
""".stripMargin
val c = firrtl.Parser.parse(input)
firrtl.Parser.parse(c.serialize)
}

an[UnsupportedVersionException] should be thrownBy {
val input = """
|FIRRTL version 1.2.0
|circuit Test :
| module Test :
| input in : UInt<1>
| in <= UInt(0)
""".stripMargin
firrtl.Parser.parse(input)
}

an[UnsupportedVersionException] should be thrownBy {
val input = """
|FIRRTL version 2.0.0
|crcuit Test :
| module Test @@#!# :
| input in1 : UInt<2>
| input in2 : UInt<3>
| output out : UInt<4>
| out[1:0] <= in1
| out[3:2] <= in2[1:0]
""".stripMargin
firrtl.Parser.parse(input)
}

// ********** Memories **********
"Memories" should "allow arbitrary ordering of fields" in {
val fields = MemTests.fieldsToSeq(MemTests.fields)
Expand Down
2 changes: 1 addition & 1 deletion src/test/scala/firrtlTests/SerializerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ object SerializerSpec {
val childModuleTabbed: String = tab(childModule)

val simpleCircuit: String =
"circuit test :\n" + childModuleTabbed + "\n\n" + testModuleTabbed + "\n"
s"FIRRTL version ${Serializer.version.serialize}\ncircuit test :\n" + childModuleTabbed + "\n\n" + testModuleTabbed + "\n"
}

class SerializerSpec extends AnyFlatSpec with Matchers {
Expand Down

0 comments on commit 19fe90b

Please sign in to comment.