aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Koenig2018-06-28 16:57:03 -0700
committerGitHub2018-06-28 16:57:03 -0700
commit3243f05a69b4b77761699be412f349a9b8b9193f (patch)
treeaf29ca891c968e718aa1a83c0fd233142395255c
parent991dba31b751f26d05835094ea49eea83f81247e (diff)
Protobuf (#832)
Add support for ProtoBuf serialization and deserialization * Add support for additional features in .proto description Features added: Info, Fixed[Type|Literal], AnalogType, Attach, Params * Add support for .pb input files This involves an API change where FIRRTL no longer implicitly adds .fir to input file names
-rw-r--r--build.sbt11
-rw-r--r--project/plugins.sbt4
-rw-r--r--src/main/proto/firrtl.proto58
-rw-r--r--src/main/scala/firrtl/Driver.scala16
-rw-r--r--src/main/scala/firrtl/ExecutionOptionsManager.scala7
-rw-r--r--src/main/scala/firrtl/WIR.scala4
-rw-r--r--src/main/scala/firrtl/proto/FromProto.scala304
-rw-r--r--src/main/scala/firrtl/proto/ToProto.scala413
-rw-r--r--src/test/scala/firrtlTests/DriverSpec.scala36
-rw-r--r--src/test/scala/firrtlTests/FirrtlSpec.scala6
-rw-r--r--src/test/scala/firrtlTests/ProtoBufSpec.scala140
-rw-r--r--test/integration/GCDTester.pbbin0 -> 4410 bytes
12 files changed, 981 insertions, 18 deletions
diff --git a/build.sbt b/build.sbt
index d52621b0..33fb8c03 100644
--- a/build.sbt
+++ b/build.sbt
@@ -68,6 +68,17 @@ libraryDependencies += "net.jcazevedo" %% "moultingyaml" % "0.4.0"
libraryDependencies += "org.json4s" %% "json4s-native" % "3.5.3"
+// Java PB
+
+enablePlugins(ProtobufPlugin)
+
+sourceDirectory in ProtobufConfig := baseDirectory.value / "src" / "main" / "proto"
+
+protobufRunProtoc in ProtobufConfig := (args =>
+ com.github.os72.protocjar.Protoc.runProtoc("-v351" +: args.toArray))
+
+javaSource in ProtobufConfig := (sourceManaged in Compile).value
+
// Assembly
assemblyJarName in assembly := "firrtl.jar"
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 40490350..1a7cb8a6 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -19,3 +19,7 @@ addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.1")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")
addSbtPlugin("com.simplytyped" % "sbt-antlr4" % "0.8.1")
+
+addSbtPlugin("com.github.gseitz" % "sbt-protobuf" % "0.6.3")
+
+libraryDependencies += "com.github.os72" % "protoc-jar" % "3.5.1.1"
diff --git a/src/main/proto/firrtl.proto b/src/main/proto/firrtl.proto
index 3e2d848c..7be042ab 100644
--- a/src/main/proto/firrtl.proto
+++ b/src/main/proto/firrtl.proto
@@ -34,9 +34,15 @@ message Firrtl {
oneof source_info {
None none = 1;
Position position = 2;
+ string text = 3;
}
}
+ message BigInt {
+ // 2's complement binary representation
+ bytes value = 1;
+ }
+
message Top {
// Required.
string name = 1;
@@ -49,9 +55,20 @@ message Firrtl {
message Module {
message ExternalModule {
+ message Parameter {
+ string id = 1;
+ oneof value {
+ BigInt integer = 2;
+ double double = 3;
+ string string = 4;
+ string raw_string = 5;
+ }
+ }
// Required.
string id = 1;
repeated Port port = 2;
+ string defined_name = 3;
+ repeated Parameter parameter = 4;
}
message UserModule {
@@ -100,6 +117,7 @@ message Firrtl {
uint32 read_latency = 5;
repeated string reader_id = 6;
repeated string writer_id = 7;
+ repeated string readwriter_id = 8;
}
message CMemory {
@@ -107,6 +125,8 @@ message Firrtl {
string id = 1;
// Required.
Type.VectorType type = 2;
+ // Required.
+ bool sync_read = 3;
}
message Instance {
@@ -141,7 +161,7 @@ message Firrtl {
message Printf {
// Required.
- bytes value = 1;
+ string value = 1;
repeated Expression arg = 2;
// Required.
Expression clk = 3;
@@ -195,6 +215,10 @@ message Firrtl {
Expression expression = 5;
}
+ message Attach {
+ repeated Expression expression = 1;
+ }
+
// Required.
oneof statement {
Wire wire = 1;
@@ -211,6 +235,7 @@ message Firrtl {
PartialConnect partial_connect = 16;
IsInvalid is_invalid = 17;
MemoryPort memory_port = 18;
+ Attach attach = 20;
}
SourceInfo source_info = 19;
@@ -256,13 +281,24 @@ message Firrtl {
uint32 size = 2;
}
+ message FixedType {
+ Width width = 1;
+ Width point = 2;
+ }
+
+ message AnalogType {
+ Width width = 3;
+ }
+
// Required.
oneof type {
UIntType uint_type = 2;
SIntType sint_type = 3;
ClockType clock_type = 4;
- RecordType record_type = 5;
+ BundleType bundle_type = 5;
VectorType vector_type = 6;
+ FixedType fixed_type = 7;
+ AnalogType analog_type = 8;
}
}
@@ -306,6 +342,12 @@ message Firrtl {
Width width = 2;
}
+ message FixedLiteral {
+ BigInt value = 1;
+ Width width = 2;
+ Width point = 3;
+ }
+
message ValidIf {
// Required.
Expression condition = 1;
@@ -376,6 +418,13 @@ message Firrtl {
OP_AS_UINT = 28;
OP_AS_SINT = 29;
OP_EXTRACT_BITS = 30;
+ OP_AS_CLOCK = 31;
+ OP_AS_FIXED_POINT = 32;
+ OP_AND_REDUCE = 33;
+ OP_OR_REDUCE = 34;
+ OP_SHIFT_BINARY_POINT_LEFT = 35;
+ OP_SHIFT_BINARY_POINT_RIGHT = 36;
+ OP_SET_BINARY_POINT = 37;
}
// Required.
@@ -384,13 +433,16 @@ message Firrtl {
repeated IntegerLiteral const = 3;
}
+ reserved 5;
+
// Required.
oneof expression {
Reference reference = 1;
UIntLiteral uint_literal = 2;
SIntLiteral sint_literal = 3;
+ FixedLiteral fixed_literal = 11;
ValidIf valid_if = 4;
- ExtractBits extract_bits = 5;
+ //ExtractBits extract_bits = 5;
Mux mux = 6;
SubField sub_field = 7;
SubIndex sub_index = 8;
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index 97d0ce4e..2315ad55 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -148,6 +148,16 @@ object Driver {
LegacyAnnotation.convertLegacyAnnos(annos)
}
+ private sealed trait FileExtension
+ private case object FirrtlFile extends FileExtension
+ private case object ProtoBufFile extends FileExtension
+
+ private def getFileExtension(filename: String): FileExtension =
+ filename.drop(filename.lastIndexOf('.')) match {
+ case ".pb" => ProtoBufFile
+ case _ => FirrtlFile // Default to FIRRTL File
+ }
+
// Useful for handling erros in the options
case class OptionsException(msg: String) extends Exception(msg)
@@ -183,7 +193,11 @@ object Driver {
}
val inputFileName = firrtlConfig.getInputFileName(optionsManager)
try {
- Parser.parseFile(inputFileName, firrtlConfig.infoMode)
+ // TODO What does InfoMode mean to ProtoBuf?
+ getFileExtension(inputFileName) match {
+ case ProtoBufFile => proto.FromProto.fromFile(inputFileName)
+ case FirrtlFile => Parser.parseFile(inputFileName, firrtlConfig.infoMode)
+ }
}
catch {
case _: FileNotFoundException =>
diff --git a/src/main/scala/firrtl/ExecutionOptionsManager.scala b/src/main/scala/firrtl/ExecutionOptionsManager.scala
index f8caf842..bb5e68a3 100644
--- a/src/main/scala/firrtl/ExecutionOptionsManager.scala
+++ b/src/main/scala/firrtl/ExecutionOptionsManager.scala
@@ -225,14 +225,15 @@ extends ComposableOptions {
}
}
- /**
- * build the input file name, taking overriding parameters
+ /** Get the name of the input file
*
+ * @note Does not implicitly add a file extension to the input file
* @param optionsManager this is needed to access build function and its common options
* @return a properly constructed input file name
*/
def getInputFileName(optionsManager: ExecutionOptionsManager): String = {
- optionsManager.getBuildFileName("fir", inputFileNameOverride)
+ if (inputFileNameOverride.nonEmpty) inputFileNameOverride
+ else optionsManager.getBuildFileName("fir", inputFileNameOverride)
}
/** Get the user-specified [[OutputConfig]]
*
diff --git a/src/main/scala/firrtl/WIR.scala b/src/main/scala/firrtl/WIR.scala
index 20da680f..29a14406 100644
--- a/src/main/scala/firrtl/WIR.scala
+++ b/src/main/scala/firrtl/WIR.scala
@@ -275,7 +275,7 @@ case class CDefMemory(
name: String,
tpe: Type,
size: Int,
- seq: Boolean) extends Statement {
+ seq: Boolean) extends Statement with HasInfo {
def serialize: String = (if (seq) "smem" else "cmem") +
s" $name : ${tpe.serialize} [$size]" + info.serialize
def mapExpr(f: Expression => Expression): Statement = this
@@ -289,7 +289,7 @@ case class CDefMPort(info: Info,
tpe: Type,
mem: String,
exps: Seq[Expression],
- direction: MPortDir) extends Statement {
+ direction: MPortDir) extends Statement with HasInfo {
def serialize: String = {
val dir = direction.serialize
s"$dir mport $name = $mem[${exps.head.serialize}], ${exps(1).serialize}" + info.serialize
diff --git a/src/main/scala/firrtl/proto/FromProto.scala b/src/main/scala/firrtl/proto/FromProto.scala
new file mode 100644
index 00000000..dda2099c
--- /dev/null
+++ b/src/main/scala/firrtl/proto/FromProto.scala
@@ -0,0 +1,304 @@
+// See LICENSE for license details.
+
+package firrtl
+package proto
+
+import java.io.{File, FileInputStream, InputStream}
+
+import collection.JavaConverters._
+import FirrtlProtos._
+import com.google.protobuf.CodedInputStream
+
+object FromProto {
+
+ /** Deserialize ProtoBuf representation of [[ir.Circuit]]
+ *
+ * @param filename Name of file containing ProtoBuf representation
+ * @return Deserialized FIRRTL Circuit
+ */
+ def fromFile(filename: String): ir.Circuit = {
+ fromInputStream(new FileInputStream(new File(filename)))
+ }
+
+ /** Deserialize ProtoBuf representation of [[ir.Circuit]]
+ *
+ * @param is InputStream containing ProtoBuf representation
+ * @return Deserialized FIRRTL Circuit
+ */
+ def fromInputStream(is: InputStream): ir.Circuit = {
+ val cistream = CodedInputStream.newInstance(is)
+ cistream.setRecursionLimit(Integer.MAX_VALUE) // Disable recursion depth check
+ val pb = firrtl.FirrtlProtos.Firrtl.parseFrom(cistream)
+ proto.FromProto.convert(pb)
+ }
+
+ // Convert from ProtoBuf message repeated Statements to FIRRRTL Block
+ private def compressStmts(stmts: Seq[ir.Statement]): ir.Statement = stmts match {
+ case Seq() => ir.EmptyStmt
+ case Seq(stmt) => stmt
+ case multiple => ir.Block(multiple)
+ }
+
+ def convert(info: Firrtl.SourceInfo): ir.Info =
+ info.getSourceInfoCase.getNumber match {
+ case Firrtl.SourceInfo.POSITION_FIELD_NUMBER =>
+ val pos = info.getPosition
+ val str = s"${pos.getFilename} ${pos.getLine}:${pos.getColumn}"
+ ir.FileInfo(ir.StringLit(str))
+ case Firrtl.SourceInfo.TEXT_FIELD_NUMBER =>
+ ir.FileInfo(ir.StringLit(info.getText))
+ // NONE_FIELD_NUMBER or anything else
+ case _ => ir.NoInfo
+ }
+
+ val convert: Map[Firrtl.Expression.PrimOp.Op, ir.PrimOp] =
+ ToProto.convert.map { case (k, v) => v -> k }
+
+ def convert(literal: Firrtl.Expression.IntegerLiteral): BigInt =
+ BigInt(literal.getValue)
+
+ def convert(bigint: Firrtl.BigInt): BigInt = BigInt(bigint.getValue.toByteArray)
+
+ def convert(uint: Firrtl.Expression.UIntLiteral): ir.UIntLiteral = {
+ val width = if (uint.hasWidth) convert(uint.getWidth) else ir.UnknownWidth
+ ir.UIntLiteral(convert(uint.getValue), width)
+ }
+
+ def convert(sint: Firrtl.Expression.SIntLiteral): ir.SIntLiteral = {
+ val width = if (sint.hasWidth) convert(sint.getWidth) else ir.UnknownWidth
+ ir.SIntLiteral(convert(sint.getValue), width)
+ }
+
+ def convert(fixed: Firrtl.Expression.FixedLiteral): ir.FixedLiteral = {
+ val width = if (fixed.hasWidth) convert(fixed.getWidth) else ir.UnknownWidth
+ val point = if (fixed.hasPoint) convert(fixed.getPoint) else ir.UnknownWidth
+ ir.FixedLiteral(convert(fixed.getValue), width, point)
+ }
+
+ def convert(subfield: Firrtl.Expression.SubField): ir.SubField =
+ ir.SubField(convert(subfield.getExpression), subfield.getField, ir.UnknownType)
+
+ def convert(index: Firrtl.Expression.SubIndex): ir.SubIndex =
+ ir.SubIndex(convert(index.getExpression), convert(index.getIndex).toInt, ir.UnknownType)
+
+ def convert(access: Firrtl.Expression.SubAccess): ir.SubAccess =
+ ir.SubAccess(convert(access.getExpression), convert(access.getIndex), ir.UnknownType)
+
+ def convert(primop: Firrtl.Expression.PrimOp): ir.DoPrim = {
+ val args = primop.getArgList.asScala.map(convert(_))
+ val consts = primop.getConstList.asScala.map(convert(_))
+ ir.DoPrim(convert(primop.getOp), args, consts, ir.UnknownType)
+ }
+
+ def convert(mux: Firrtl.Expression.Mux): ir.Mux =
+ ir.Mux(convert(mux.getCondition), convert(mux.getTValue), convert(mux.getFValue), ir.UnknownType)
+
+ def convert(expr: Firrtl.Expression): ir.Expression = {
+ import Firrtl.Expression._
+ expr.getExpressionCase.getNumber match {
+ case REFERENCE_FIELD_NUMBER => ir.Reference(expr.getReference.getId, ir.UnknownType)
+ case SUB_FIELD_FIELD_NUMBER => convert(expr.getSubField)
+ case SUB_INDEX_FIELD_NUMBER => convert(expr.getSubIndex)
+ case SUB_ACCESS_FIELD_NUMBER => convert(expr.getSubAccess)
+ case UINT_LITERAL_FIELD_NUMBER => convert(expr.getUintLiteral)
+ case SINT_LITERAL_FIELD_NUMBER => convert(expr.getSintLiteral)
+ case FIXED_LITERAL_FIELD_NUMBER => convert(expr.getFixedLiteral)
+ case PRIM_OP_FIELD_NUMBER => convert(expr.getPrimOp)
+ case MUX_FIELD_NUMBER => convert(expr.getMux)
+ }
+ }
+
+ def convert(con: Firrtl.Statement.Connect, info: Firrtl.SourceInfo): ir.Connect =
+ ir.Connect(convert(info), convert(con.getLocation), convert(con.getExpression))
+
+ def convert(con: Firrtl.Statement.PartialConnect, info: Firrtl.SourceInfo): ir.PartialConnect =
+ ir.PartialConnect(convert(info), convert(con.getLocation), convert(con.getExpression))
+
+ def convert(wire: Firrtl.Statement.Wire, info: Firrtl.SourceInfo): ir.DefWire =
+ ir.DefWire(convert(info), wire.getId, convert(wire.getType))
+
+ def convert(reg: Firrtl.Statement.Register, info: Firrtl.SourceInfo): ir.DefRegister =
+ ir.DefRegister(convert(info), reg.getId, convert(reg.getType), convert(reg.getClock),
+ convert(reg.getReset), convert(reg.getInit))
+
+ def convert(node: Firrtl.Statement.Node, info: Firrtl.SourceInfo): ir.DefNode =
+ ir.DefNode(convert(info), node.getId, convert(node.getExpression))
+
+ def convert(inst: Firrtl.Statement.Instance, info: Firrtl.SourceInfo): ir.DefInstance =
+ ir.DefInstance(convert(info), inst.getId, inst.getModuleId)
+
+ def convert(when: Firrtl.Statement.When, info: Firrtl.SourceInfo): ir.Conditionally = {
+ val conseq = compressStmts(when.getConsequentList.asScala.map(convert(_)))
+ val alt = compressStmts(when.getOtherwiseList.asScala.map(convert(_)))
+ ir.Conditionally(convert(info), convert(when.getPredicate), conseq, alt)
+ }
+
+ def convert(cmem: Firrtl.Statement.CMemory, info: Firrtl.SourceInfo): ir.Statement = {
+ val vtpe = convert(cmem.getType)
+ CDefMemory(convert(info), cmem.getId, vtpe.tpe, vtpe.size, cmem.getSyncRead)
+ }
+
+ import Firrtl.Statement.MemoryPort.Direction._
+ def convert(mportdir: Firrtl.Statement.MemoryPort.Direction): MPortDir = mportdir match {
+ case MEMORY_PORT_DIRECTION_INFER => MInfer
+ case MEMORY_PORT_DIRECTION_READ => MRead
+ case MEMORY_PORT_DIRECTION_WRITE => MWrite
+ case MEMORY_PORT_DIRECTION_READ_WRITE => MReadWrite
+ }
+
+ def convert(port: Firrtl.Statement.MemoryPort, info: Firrtl.SourceInfo): CDefMPort = {
+ val exprs = Seq(convert(port.getMemoryIndex), convert(port.getExpression))
+ CDefMPort(convert(info), port.getId, ir.UnknownType, port.getMemoryId, exprs, convert(port.getDirection))
+ }
+
+ def convert(printf: Firrtl.Statement.Printf, info: Firrtl.SourceInfo): ir.Print = {
+ val args = printf.getArgList.asScala.map(convert(_))
+ val str = ir.StringLit(printf.getValue)
+ ir.Print(convert(info), str, args, convert(printf.getClk), convert(printf.getEn))
+ }
+
+ def convert(stop: Firrtl.Statement.Stop, info: Firrtl.SourceInfo): ir.Stop =
+ ir.Stop(convert(info), stop.getReturnValue, convert(stop.getClk), convert(stop.getEn))
+
+ def convert(mem: Firrtl.Statement.Memory, info: Firrtl.SourceInfo): ir.DefMemory = {
+ val dtype = convert(mem.getType)
+ val rs = mem.getReaderIdList.asScala
+ val ws = mem.getWriterIdList.asScala
+ val rws = mem.getReadwriterIdList.asScala
+ ir.DefMemory(convert(info), mem.getId, dtype, mem.getDepth, mem.getWriteLatency, mem.getReadLatency,
+ rs, ws, rws, None)
+ }
+
+ def convert(attach: Firrtl.Statement.Attach, info: Firrtl.SourceInfo): ir.Attach = {
+ val exprs = attach.getExpressionList.asScala.map(convert(_))
+ ir.Attach(convert(info), exprs)
+ }
+
+ def convert(stmt: Firrtl.Statement): ir.Statement = {
+ import Firrtl.Statement._
+ val info = stmt.getSourceInfo
+ stmt.getStatementCase.getNumber match {
+ case NODE_FIELD_NUMBER => convert(stmt.getNode, info)
+ case CONNECT_FIELD_NUMBER => convert(stmt.getConnect, info)
+ case PARTIAL_CONNECT_FIELD_NUMBER => convert(stmt.getPartialConnect, info)
+ case WIRE_FIELD_NUMBER => convert(stmt.getWire, info)
+ case REGISTER_FIELD_NUMBER => convert(stmt.getRegister, info)
+ case WHEN_FIELD_NUMBER => convert(stmt.getWhen, info)
+ case INSTANCE_FIELD_NUMBER => convert(stmt.getInstance, info)
+ case PRINTF_FIELD_NUMBER => convert(stmt.getPrintf, info)
+ case STOP_FIELD_NUMBER => convert(stmt.getStop, info)
+ case MEMORY_FIELD_NUMBER => convert(stmt.getMemory, info)
+ case IS_INVALID_FIELD_NUMBER =>
+ ir.IsInvalid(convert(info), convert(stmt.getIsInvalid.getExpression))
+ case CMEMORY_FIELD_NUMBER => convert(stmt.getCmemory, info)
+ case MEMORY_PORT_FIELD_NUMBER => convert(stmt.getMemoryPort, info)
+ case ATTACH_FIELD_NUMBER => convert(stmt.getAttach, info)
+ }
+ }
+
+ /** Converts ProtoBuf width to FIRRTL width
+ *
+ * @note Checks for UnknownWidth must be done on the parent object
+ * @param width ProtoBuf width representation
+ * @return IntWidth equivalent of the ProtoBuf width, default is 0
+ */
+ def convert(width: Firrtl.Width): ir.IntWidth = ir.IntWidth(width.getValue)
+
+ def convert(ut: Firrtl.Type.UIntType): ir.UIntType = {
+ val w = if (ut.hasWidth) convert(ut.getWidth) else ir.UnknownWidth
+ ir.UIntType(w)
+ }
+
+ def convert(st: Firrtl.Type.SIntType): ir.SIntType = {
+ val w = if (st.hasWidth) convert(st.getWidth) else ir.UnknownWidth
+ ir.SIntType(w)
+ }
+
+ def convert(fixed: Firrtl.Type.FixedType): ir.FixedType = {
+ val w = if (fixed.hasWidth) convert(fixed.getWidth) else ir.UnknownWidth
+ val p = if (fixed.hasPoint) convert(fixed.getPoint) else ir.UnknownWidth
+ ir.FixedType(w, p)
+ }
+
+ def convert(analog: Firrtl.Type.AnalogType): ir.AnalogType = {
+ val w = if (analog.hasWidth) convert(analog.getWidth) else ir.UnknownWidth
+ ir.AnalogType(w)
+ }
+
+ def convert(field: Firrtl.Type.BundleType.Field): ir.Field = {
+ val flip = if (field.getIsFlipped) ir.Flip else ir.Default
+ ir.Field(field.getId, flip, convert(field.getType))
+ }
+
+ def convert(vtpe: Firrtl.Type.VectorType): ir.VectorType =
+ ir.VectorType(convert(vtpe.getType), vtpe.getSize)
+
+ def convert(tpe: Firrtl.Type): ir.Type = {
+ import Firrtl.Type._
+ tpe.getTypeCase.getNumber match {
+ case UINT_TYPE_FIELD_NUMBER => convert(tpe.getUintType)
+ case SINT_TYPE_FIELD_NUMBER => convert(tpe.getSintType)
+ case FIXED_TYPE_FIELD_NUMBER => convert(tpe.getFixedType)
+ case CLOCK_TYPE_FIELD_NUMBER => ir.ClockType
+ case ANALOG_TYPE_FIELD_NUMBER => convert(tpe.getAnalogType)
+ case BUNDLE_TYPE_FIELD_NUMBER =>
+ ir.BundleType(tpe.getBundleType.getFieldList.asScala.map(convert(_)))
+ case VECTOR_TYPE_FIELD_NUMBER => convert(tpe.getVectorType)
+ }
+ }
+
+ def convert(dir: Firrtl.Port.Direction): ir.Direction = {
+ dir match {
+ case Firrtl.Port.Direction.PORT_DIRECTION_IN => ir.Input
+ case Firrtl.Port.Direction.PORT_DIRECTION_OUT => ir.Output
+ }
+ }
+
+ def convert(port: Firrtl.Port): ir.Port = {
+ val dir = convert(port.getDirection)
+ val tpe = convert(port.getType)
+ ir.Port(ir.NoInfo, port.getId, dir, tpe)
+ }
+
+ def convert(param: Firrtl.Module.ExternalModule.Parameter): ir.Param = {
+ import Firrtl.Module.ExternalModule.Parameter._
+ val name = param.getId
+ param.getValueCase.getNumber match {
+ case INTEGER_FIELD_NUMBER => ir.IntParam(name, convert(param.getInteger))
+ case DOUBLE_FIELD_NUMBER => ir.DoubleParam(name, param.getDouble)
+ case STRING_FIELD_NUMBER => ir.StringParam(name, ir.StringLit(param.getString))
+ case RAW_STRING_FIELD_NUMBER => ir.RawStringParam(name, param.getRawString)
+ }
+ }
+
+ def convert(module: Firrtl.Module.UserModule): ir.Module = {
+ val name = module.getId
+ val ports = module.getPortList.asScala.map(convert(_))
+ val stmts = module.getStatementList.asScala.map(convert(_))
+ ir.Module(ir.NoInfo, name, ports, ir.Block(stmts))
+ }
+
+ def convert(module: Firrtl.Module.ExternalModule): ir.ExtModule = {
+ val name = module.getId
+ val ports = module.getPortList.asScala.map(convert(_))
+ val defname = module.getDefinedName
+ val params = module.getParameterList.asScala.map(convert(_))
+ ir.ExtModule(ir.NoInfo, name, ports, defname, params)
+ }
+
+ def convert(module: Firrtl.Module): ir.DefModule =
+ if (module.hasUserModule) convert(module.getUserModule)
+ else {
+ require(module.hasExternalModule, "Module must have Module or ExtModule")
+ convert(module.getExternalModule)
+ }
+
+ def convert(proto: Firrtl): ir.Circuit = {
+ require(proto.getCircuitCount == 1, "Only 1 circuit is currently supported")
+ val c = proto.getCircuit(0)
+ require(c.getTopCount == 1, "Only 1 top is currently supported")
+ val modules = c.getModuleList.asScala.map(convert(_))
+ val top = c.getTop(0).getName
+ ir.Circuit(ir.NoInfo, modules, top)
+ }
+}
diff --git a/src/main/scala/firrtl/proto/ToProto.scala b/src/main/scala/firrtl/proto/ToProto.scala
new file mode 100644
index 00000000..b3fb9a0c
--- /dev/null
+++ b/src/main/scala/firrtl/proto/ToProto.scala
@@ -0,0 +1,413 @@
+// See LICENSE for license details.
+
+package firrtl
+package proto
+
+import java.io.{BufferedOutputStream, OutputStream}
+
+import FirrtlProtos._
+import Firrtl.Expression.PrimOp.Op
+import com.google.protobuf.{CodedOutputStream, WireFormat}
+import firrtl.PrimOps._
+
+import scala.collection.JavaConverters._
+
+object ToProto {
+
+
+ /** Serialize a FIRRTL Circuit to an Output Stream as a ProtoBuf message
+ *
+ * @param ostream Output stream that will be written
+ * @param circuit The Circuit to serialize
+ */
+ def writeToStream(ostream: OutputStream, circuit: ir.Circuit): Unit = {
+ writeToStreamFast(ostream, circuit.info, circuit.modules.map(() => _), circuit.main)
+ }
+
+ /** Serialized a deconstructed Circuit with lazy Modules
+ *
+ * This serializer allows intermediate objects to be garbage collected during serialization
+ * to save time and memory
+ *
+ * @param ostream Output stream that will be written
+ * @param info Info of Circuit
+ * @param modules Functions to generate Modules lazily
+ * @param main Top-level module of the Circuit
+ */
+ // Note this function is sensitive to changes to the Firrtl and Circuit protobuf message definitions
+ def writeToStreamFast(
+ ostream: OutputStream,
+ info: ir.Info,
+ modules: Seq[() => ir.DefModule],
+ main: String
+ ): Unit = {
+ val costream = CodedOutputStream.newInstance(ostream)
+
+ // Write each module for the circuit
+ val ostreamInner = new java.io.ByteArrayOutputStream()
+ val costreamInner = CodedOutputStream.newInstance(ostreamInner)
+ for (mod <- modules) {
+ costreamInner.writeMessage(Firrtl.Circuit.MODULE_FIELD_NUMBER, convert(mod()).build)
+ }
+ val top = Firrtl.Top.newBuilder().setName(main).build
+ costreamInner.writeMessage(Firrtl.Circuit.TOP_FIELD_NUMBER, top)
+
+ // Write Circuit header first
+ costream.writeTag(Firrtl.CIRCUIT_FIELD_NUMBER, WireFormat.WIRETYPE_LENGTH_DELIMITED)
+ costream.writeUInt32NoTag(costreamInner.getTotalBytesWritten)
+ costream.flush()
+
+ // Write Modules
+ costreamInner.flush()
+ ostreamInner.writeTo(ostream)
+ ostreamInner.flush()
+ }
+
+ val convert: Map[ir.PrimOp, Op] = Map(
+ Add -> Op.OP_ADD,
+ Sub -> Op.OP_SUB,
+ Mul -> Op.OP_TIMES,
+ Div -> Op.OP_DIVIDE,
+ Rem -> Op.OP_REM,
+ Lt -> Op.OP_LESS,
+ Leq -> Op.OP_LESS_EQ,
+ Gt -> Op.OP_GREATER,
+ Geq -> Op.OP_GREATER_EQ,
+ Eq -> Op.OP_EQUAL,
+ Neq -> Op.OP_NOT_EQUAL,
+ Pad -> Op.OP_PAD,
+ AsUInt -> Op.OP_AS_UINT,
+ AsSInt -> Op.OP_AS_SINT,
+ AsClock -> Op.OP_AS_CLOCK,
+ AsFixedPoint -> Op.OP_AS_FIXED_POINT,
+ Shl -> Op.OP_SHIFT_LEFT,
+ Shr -> Op.OP_SHIFT_RIGHT,
+ Dshl -> Op.OP_DYNAMIC_SHIFT_LEFT,
+ Dshr -> Op.OP_DYNAMIC_SHIFT_RIGHT,
+ Cvt -> Op.OP_CONVERT,
+ Neg -> Op.OP_NEG,
+ Not -> Op.OP_BIT_NOT,
+ And -> Op.OP_BIT_AND,
+ Or -> Op.OP_BIT_OR,
+ Xor -> Op.OP_BIT_XOR,
+ Andr -> Op.OP_AND_REDUCE,
+ Orr -> Op.OP_OR_REDUCE,
+ Xorr -> Op.OP_XOR_REDUCE,
+ Cat -> Op.OP_CONCAT,
+ Bits -> Op.OP_EXTRACT_BITS,
+ Head -> Op.OP_HEAD,
+ Tail -> Op.OP_TAIL,
+ BPShl -> Op.OP_SHIFT_BINARY_POINT_LEFT,
+ BPShr -> Op.OP_SHIFT_BINARY_POINT_RIGHT,
+ BPSet -> Op.OP_SET_BINARY_POINT
+ )
+
+ def convertToIntegerLiteral(value: BigInt): Firrtl.Expression.IntegerLiteral.Builder = {
+ Firrtl.Expression.IntegerLiteral.newBuilder()
+ .setValue(value.toString)
+ }
+
+ def convertToBigInt(value: BigInt): Firrtl.BigInt.Builder = {
+ Firrtl.BigInt.newBuilder()
+ .setValue(com.google.protobuf.ByteString.copyFrom(value.toByteArray))
+ }
+
+ def convert(info: ir.Info): Firrtl.SourceInfo.Builder = {
+ val ib = Firrtl.SourceInfo.newBuilder()
+ info match {
+ case ir.NoInfo =>
+ ib.setNone(Firrtl.SourceInfo.None.newBuilder)
+ case ir.FileInfo(ir.StringLit(text)) =>
+ ib.setText(text)
+ // TODO properly implement MultiInfo
+ case ir.MultiInfo(infos) =>
+ val x = if (infos.nonEmpty) infos.head else ir.NoInfo
+ convert(x)
+ }
+ }
+
+ def convert(expr: ir.Expression): Firrtl.Expression.Builder = {
+ val eb = Firrtl.Expression.newBuilder()
+ expr match {
+ case ir.Reference(name, _) =>
+ val rb = Firrtl.Expression.Reference.newBuilder()
+ .setId(name)
+ eb.setReference(rb)
+ case ir.SubField(e, name, _) =>
+ val sb = Firrtl.Expression.SubField.newBuilder()
+ .setExpression(convert(e))
+ .setField(name)
+ eb.setSubField(sb)
+ case ir.SubIndex(e, value, _) =>
+ val sb = Firrtl.Expression.SubIndex.newBuilder()
+ .setExpression(convert(e))
+ .setIndex(convertToIntegerLiteral(value))
+ eb.setSubIndex(sb)
+ case ir.SubAccess(e, index, _) =>
+ val sb = Firrtl.Expression.SubAccess.newBuilder()
+ .setExpression(convert(e))
+ .setIndex(convert(index))
+ eb.setSubAccess(sb)
+ case ir.UIntLiteral(value, width) =>
+ val ub = Firrtl.Expression.UIntLiteral.newBuilder()
+ .setValue(convertToIntegerLiteral(value))
+ convert(width).foreach(ub.setWidth)
+ eb.setUintLiteral(ub)
+ case ir.SIntLiteral(value, width) =>
+ val sb = Firrtl.Expression.SIntLiteral.newBuilder()
+ .setValue(convertToIntegerLiteral(value))
+ convert(width).foreach(sb.setWidth)
+ eb.setSintLiteral(sb)
+ case ir.FixedLiteral(value, width, point) =>
+ val fb = Firrtl.Expression.FixedLiteral.newBuilder()
+ .setValue(convertToBigInt(value))
+ convert(width).foreach(fb.setWidth)
+ convert(point).foreach(fb.setPoint)
+ eb.setFixedLiteral(fb)
+ case ir.DoPrim(op, args, consts, _) =>
+ val db = Firrtl.Expression.PrimOp.newBuilder()
+ .setOp(convert(op))
+ consts.foreach(c => db.addConst(convertToIntegerLiteral(c)))
+ args.foreach(a => db.addArg(convert(a)))
+ eb.setPrimOp(db)
+ case ir.Mux(cond, tval, fval, _) =>
+ val mb = Firrtl.Expression.Mux.newBuilder()
+ .setCondition(convert(cond))
+ .setTValue(convert(tval))
+ .setFValue(convert(fval))
+ eb.setMux(mb)
+ }
+ }
+
+ def convert(dir: MPortDir): Firrtl.Statement.MemoryPort.Direction = {
+ import Firrtl.Statement.MemoryPort.Direction._
+ dir match {
+ case MInfer => MEMORY_PORT_DIRECTION_INFER
+ case MRead => MEMORY_PORT_DIRECTION_READ
+ case MWrite => MEMORY_PORT_DIRECTION_WRITE
+ case MReadWrite => MEMORY_PORT_DIRECTION_READ_WRITE
+ }
+ }
+
+ def convert(stmt: ir.Statement): Seq[Firrtl.Statement.Builder] = {
+ stmt match {
+ case ir.Block(stmts) => stmts.flatMap(convert(_))
+ case ir.EmptyStmt => Seq.empty
+ case other =>
+ val sb = Firrtl.Statement.newBuilder()
+ other match {
+ case ir.DefNode(_, name, expr) =>
+ val nb = Firrtl.Statement.Node.newBuilder()
+ .setId(name)
+ .setExpression(convert(expr))
+ sb.setNode(nb)
+ case ir.DefWire(_, name, tpe) =>
+ val wb = Firrtl.Statement.Wire.newBuilder()
+ .setId(name)
+ .setType(convert(tpe))
+ sb.setWire(wb)
+ case ir.DefRegister(_, name, tpe, clock, reset, init) =>
+ val rb = Firrtl.Statement.Register.newBuilder()
+ .setId(name)
+ .setType(convert(tpe))
+ .setClock(convert(clock))
+ .setReset(convert(reset))
+ .setInit(convert(init))
+ sb.setRegister(rb)
+ case ir.DefInstance(_, name, module) =>
+ val ib = Firrtl.Statement.Instance.newBuilder()
+ .setId(name)
+ .setModuleId(module)
+ sb.setInstance(ib)
+ case ir.Connect(_, loc, expr) =>
+ val cb = Firrtl.Statement.Connect.newBuilder()
+ .setLocation(convert(loc))
+ .setExpression(convert(expr))
+ sb.setConnect(cb)
+ case ir.PartialConnect(_, loc, expr) =>
+ val cb = Firrtl.Statement.PartialConnect.newBuilder()
+ .setLocation(convert(loc))
+ .setExpression(convert(expr))
+ sb.setPartialConnect(cb)
+ case ir.Conditionally(_, pred, conseq, alt) =>
+ val cs = convert(conseq)
+ val as = convert(alt)
+ val wb = Firrtl.Statement.When.newBuilder()
+ .setPredicate(convert(pred))
+ cs.foreach(wb.addConsequent)
+ as.foreach(wb.addOtherwise)
+ sb.setWhen(wb)
+ case ir.Print(_, string, args, clk, en) =>
+ val pb = Firrtl.Statement.Printf.newBuilder()
+ .setValue(string.string)
+ .setClk(convert(clk))
+ .setEn(convert(en))
+ args.foreach(a => pb.addArg(convert(a)))
+ sb.setPrintf(pb)
+ case ir.Stop(_, ret, clk, en) =>
+ val stopb = Firrtl.Statement.Stop.newBuilder()
+ .setReturnValue(ret)
+ .setClk(convert(clk))
+ .setEn(convert(en))
+ sb.setStop(stopb)
+ case ir.IsInvalid(_, expr) =>
+ val ib = Firrtl.Statement.IsInvalid.newBuilder()
+ .setExpression(convert(expr))
+ sb.setIsInvalid(ib)
+ case ir.DefMemory(_, name, dtype, depth, wlat, rlat, rs, ws, rws, _) =>
+ val mem = Firrtl.Statement.Memory.newBuilder()
+ .setId(name)
+ .setType(convert(dtype))
+ .setDepth(depth)
+ .setWriteLatency(wlat)
+ .setReadLatency(rlat)
+ mem.addAllReaderId(rs.asJava)
+ mem.addAllWriterId(ws.asJava)
+ mem.addAllReadwriterId(rws.asJava)
+ sb.setMemory(mem)
+ case CDefMemory(_, name, tpe, size, seq) =>
+ val tpeb = convert(ir.VectorType(tpe, size))
+ val mb = Firrtl.Statement.CMemory.newBuilder()
+ .setId(name)
+ .setType(tpeb)
+ .setSyncRead(seq)
+ sb.setCmemory(mb)
+ case CDefMPort(_, name, _, mem, exprs, dir) =>
+ val pb = Firrtl.Statement.MemoryPort.newBuilder()
+ .setId(name)
+ .setMemoryId(mem)
+ .setMemoryIndex(convert(exprs.head))
+ .setExpression(convert(exprs(1)))
+ .setDirection(convert(dir))
+ sb.setMemoryPort(pb)
+ case ir.Attach(_, exprs) =>
+ val ab = Firrtl.Statement.Attach.newBuilder()
+ exprs.foreach(e => ab.addExpression(convert(e)))
+ sb.setAttach(ab)
+ }
+ stmt match {
+ case hasInfo: ir.HasInfo => sb.setSourceInfo(convert(hasInfo.info))
+ case _ => // Do nothing
+ }
+ Seq(sb)
+ }
+ }
+
+ def convert(field: ir.Field): Firrtl.Type.BundleType.Field.Builder = {
+ val b = Firrtl.Type.BundleType.Field.newBuilder()
+ .setId(field.name)
+ .setIsFlipped(field.flip == ir.Flip)
+ .setType(convert(field.tpe))
+ b
+ }
+
+ /** Converts a Width to a ProtoBuf Width Builder
+ *
+ * @param width Input width
+ * @return Option width where None means the width field should be cleared in the parent object
+ */
+ def convert(width: ir.Width): Option[Firrtl.Width.Builder] = width match {
+ case ir.IntWidth(w) => Some(Firrtl.Width.newBuilder().setValue(w.toInt))
+ case ir.UnknownWidth => None
+ }
+
+ def convert(vtpe: ir.VectorType): Firrtl.Type.VectorType.Builder =
+ Firrtl.Type.VectorType.newBuilder()
+ .setType(convert(vtpe.tpe))
+ .setSize(vtpe.size)
+
+ def convert(tpe: ir.Type): Firrtl.Type.Builder = {
+ val tb = Firrtl.Type.newBuilder()
+ tpe match {
+ case ir.UIntType(width) =>
+ val ut = Firrtl.Type.UIntType.newBuilder()
+ convert(width).foreach(ut.setWidth)
+ tb.setUintType(ut)
+ case ir.SIntType(width) =>
+ val st = Firrtl.Type.SIntType.newBuilder()
+ convert(width).foreach(st.setWidth)
+ tb.setSintType(st)
+ case ir.FixedType(width, point) =>
+ val ft = Firrtl.Type.FixedType.newBuilder()
+ convert(width).foreach(ft.setWidth)
+ convert(point).foreach(ft.setPoint)
+ tb.setFixedType(ft)
+ case ir.ClockType =>
+ val ct = Firrtl.Type.ClockType.newBuilder()
+ tb.setClockType(ct)
+ case ir.AnalogType(width) =>
+ val at = Firrtl.Type.AnalogType.newBuilder()
+ convert(width).foreach(at.setWidth)
+ tb.setAnalogType(at)
+ case ir.BundleType(fields) =>
+ val bt = Firrtl.Type.BundleType.newBuilder()
+ fields.foreach(f => bt.addField(convert(f)))
+ tb.setBundleType(bt)
+ case vtpe: ir.VectorType =>
+ val vtb = convert(vtpe)
+ tb.setVectorType(vtb)
+ }
+ }
+
+ def convert(direction: ir.Direction): Firrtl.Port.Direction = direction match {
+ case ir.Input => Firrtl.Port.Direction.PORT_DIRECTION_IN
+ case ir.Output => Firrtl.Port.Direction.PORT_DIRECTION_OUT
+ }
+
+ def convert(port: ir.Port): Firrtl.Port.Builder = {
+ Firrtl.Port.newBuilder()
+ .setId(port.name)
+ .setDirection(convert(port.direction))
+ .setType(convert(port.tpe))
+ }
+
+ def convert(param: ir.Param): Firrtl.Module.ExternalModule.Parameter.Builder = {
+ import Firrtl.Module.ExternalModule._
+ val pb = Parameter.newBuilder()
+ .setId(param.name)
+ param match {
+ case ir.IntParam(_, value) =>
+ pb.setInteger(convertToBigInt(value))
+ case ir.DoubleParam(_, value) =>
+ pb.setDouble(value)
+ case ir.StringParam(_, ir.StringLit(value)) =>
+ pb.setString(value)
+ case ir.RawStringParam(_, value) =>
+ pb.setRawString(value)
+ }
+ }
+
+ def convert(module: ir.DefModule): Firrtl.Module.Builder = {
+ val ports = module.ports.map(convert(_))
+ val b = Firrtl.Module.newBuilder()
+ module match {
+ case mod: ir.Module =>
+ val stmts = convert(mod.body)
+ val mb = Firrtl.Module.UserModule.newBuilder()
+ .setId(mod.name)
+ ports.foreach(mb.addPort)
+ stmts.foreach(mb.addStatement)
+ b.setUserModule(mb)
+ case ext: ir.ExtModule =>
+ val eb = Firrtl.Module.ExternalModule.newBuilder()
+ .setId(ext.name)
+ .setDefinedName(ext.defname)
+ ports.foreach(eb.addPort)
+ val params = ext.params.map(convert(_))
+ params.foreach(eb.addParameter)
+ b.setExternalModule(eb)
+ }
+ }
+
+ def convert(circuit: ir.Circuit): Firrtl = {
+ val moduleBuilders = circuit.modules.map(convert(_))
+ val cb = Firrtl.Circuit.newBuilder
+ .addTop(Firrtl.Top.newBuilder().setName(circuit.main))
+ for (m <- moduleBuilders) {
+ cb.addModule(m)
+ }
+ Firrtl.newBuilder()
+ .addCircuit(cb.build())
+ .build()
+ }
+}
diff --git a/src/test/scala/firrtlTests/DriverSpec.scala b/src/test/scala/firrtlTests/DriverSpec.scala
index 4afd5674..4cc7bc90 100644
--- a/src/test/scala/firrtlTests/DriverSpec.scala
+++ b/src/test/scala/firrtlTests/DriverSpec.scala
@@ -2,22 +2,18 @@
package firrtlTests
-import java.io.{File, FileWriter}
-import org.scalatest.{FreeSpec, Matchers}
+import java.io.{File, FileInputStream, FileWriter}
+import org.scalatest.{FreeSpec, Matchers}
import firrtl.passes.{InlineAnnotation, InlineInstances}
-import firrtl.passes.memlib.{
- InferReadWrite,
- InferReadWriteAnnotation,
- ReplSeqMem,
- ReplSeqMemAnnotation
-}
+import firrtl.passes.memlib.{InferReadWrite, InferReadWriteAnnotation, ReplSeqMem, ReplSeqMemAnnotation}
import firrtl.transforms.BlackBoxTargetDirAnno
import firrtl._
import firrtl.annotations._
import firrtl.util.BackendCompilationUtilities
-import scala.util.{Try, Success, Failure}
+import scala.io.Source
+import scala.util.{Failure, Success, Try}
class ExceptingTransform extends Transform {
def inputForm = HighForm
@@ -416,6 +412,28 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
}
}
+ "The Driver is sensitive to the file extension of input files" - {
+ val design = "GCDTester"
+ val outputDir = createTestDirectory("DriverFileExtensionSensitivity")
+ val verilogFromFir = new File(outputDir, s"$design.fromfir.v")
+ val verilogFromPb = new File(outputDir, s"$design.frompb.v")
+ val commonArgs = Array("-X", "verilog", "--info-mode", "use")
+ ".fir means FIRRTL file" in {
+ val inFile = new File(getClass.getResource(s"/integration/$design.fir").getFile)
+ val args = Array("-i", inFile.getAbsolutePath, "-o", verilogFromFir.getAbsolutePath) ++ commonArgs
+ Driver.execute(args)
+ }
+ ".pb means ProtoBuf file" in {
+ val inFile = new File(getClass.getResource(s"/integration/$design.pb").getFile)
+ val args = Array("-i", inFile.getAbsolutePath, "-o", verilogFromPb.getAbsolutePath) ++ commonArgs
+ Driver.execute(args)
+ }
+ "Both paths do the same thing" in {
+ val s1 = Source.fromFile(verilogFromFir).mkString
+ val s2 = Source.fromFile(verilogFromPb).mkString
+ s1 should equal (s2)
+ }
+ }
"Directory deleter is handy for cleaning up after tests" - {
"for example making a directory tree, and deleting it looks like" in {
diff --git a/src/test/scala/firrtlTests/FirrtlSpec.scala b/src/test/scala/firrtlTests/FirrtlSpec.scala
index 861d1745..01ae0431 100644
--- a/src/test/scala/firrtlTests/FirrtlSpec.scala
+++ b/src/test/scala/firrtlTests/FirrtlSpec.scala
@@ -101,6 +101,12 @@ trait FirrtlMatchers extends Matchers {
require(!s.contains("\n"))
s.replaceAll("\\s+", " ").trim
}
+ /** Helper to make circuits that are the same appear the same */
+ def canonicalize(circuit: Circuit): Circuit = {
+ import firrtl.Mappers._
+ def onModule(mod: DefModule) = mod.map(firrtl.Utils.squashEmpty)
+ circuit.map(onModule)
+ }
def parse(str: String) = Parser.parse(str.split("\n").toIterator, UseInfo)
/** Helper for executing tests
* compiler will be run on input then emitted result will each be split into
diff --git a/src/test/scala/firrtlTests/ProtoBufSpec.scala b/src/test/scala/firrtlTests/ProtoBufSpec.scala
new file mode 100644
index 00000000..2a60eab5
--- /dev/null
+++ b/src/test/scala/firrtlTests/ProtoBufSpec.scala
@@ -0,0 +1,140 @@
+// See LICENSE for license details.
+
+package firrtlTests
+
+import java.io.{ByteArrayInputStream, ByteArrayOutputStream}
+
+import firrtl.FirrtlProtos.Firrtl
+import firrtl._
+import firrtl.ir._
+import firrtl.Mappers._
+
+class ProtoBufSpec extends FirrtlFlatSpec {
+
+ /** Tests in src/test/resource/ in .fir format
+ *
+ * @note These tests rely on the ANTLR Parser
+ */
+ case class FirrtlResourceTest(name: String, resourceDir: String)
+
+ val firrtlResourceTests = List(
+ FirrtlResourceTest("GCDTester", "/integration"),
+ FirrtlResourceTest("RightShiftTester", "/integration"),
+ FirrtlResourceTest("MemTester", "/integration"),
+ FirrtlResourceTest("PipeTester", "/integration"),
+ FirrtlResourceTest("Rob", "/regress"),
+ FirrtlResourceTest("RocketCore", "/regress"),
+ FirrtlResourceTest("ICache", "/regress"),
+ FirrtlResourceTest("FPU", "/regress")
+ )
+
+ for (FirrtlResourceTest(name, dir) <- firrtlResourceTests) {
+ s"$name" should "work with Protobuf serialization and deserialization" in {
+ val stream = getClass.getResourceAsStream(s"$dir/$name.fir")
+ val circuit = parse(scala.io.Source.fromInputStream(stream).getLines.mkString("\n"))
+
+ // Test ToProto and FromProto
+ val protobuf = proto.ToProto.convert(circuit)
+ val pcircuit = proto.FromProto.convert(protobuf)
+ canonicalize(circuit).serialize should equal(canonicalize(pcircuit).serialize)
+
+ // Test ProtoBuf generated serialization and deserialization
+ val ostream = new java.io.ByteArrayOutputStream()
+ protobuf.writeTo(ostream)
+ val istream = new java.io.ByteArrayInputStream(ostream.toByteArray)
+ val cistream = com.google.protobuf.CodedInputStream.newInstance(istream)
+ cistream.setRecursionLimit(Integer.MAX_VALUE)
+ val protobuf2 = firrtl.FirrtlProtos.Firrtl.parseFrom(cistream)
+ protobuf2 should equal (protobuf)
+
+ // Test that our faster serialization matches generated serialization
+ val ostream2 = new java.io.ByteArrayOutputStream
+ proto.ToProto.writeToStream(ostream2, circuit)
+ ostream2.toByteArray.toList should equal (ostream.toByteArray.toList)
+ }
+ }
+
+ // ********** Focused Tests **********
+ // The goal is to fill coverage holes left after the above
+
+ behavior of "ProtoBuf serialization and deserialization"
+ import firrtl.proto._
+
+ it should "support UnknownWidth" in {
+ // Note that this has to be handled in the parent object so we need to test everything that has a width
+ val uint = ir.UIntType(ir.UnknownWidth)
+ FromProto.convert(ToProto.convert(uint).build) should equal (uint)
+
+ val sint = ir.SIntType(ir.UnknownWidth)
+ FromProto.convert(ToProto.convert(sint).build) should equal (sint)
+
+ val ftpe = ir.FixedType(ir.UnknownWidth, ir.UnknownWidth)
+ FromProto.convert(ToProto.convert(ftpe).build) should equal (ftpe)
+
+ val atpe = ir.AnalogType(ir.UnknownWidth)
+ FromProto.convert(ToProto.convert(atpe).build) should equal (atpe)
+
+ val ulit = ir.UIntLiteral(123, ir.UnknownWidth)
+ FromProto.convert(ToProto.convert(ulit).build) should equal (ulit)
+
+ val slit = ir.SIntLiteral(-123, ir.UnknownWidth)
+ FromProto.convert(ToProto.convert(slit).build) should equal (slit)
+
+ val flit = ir.FixedLiteral(-123, ir.UnknownWidth, ir.UnknownWidth)
+ FromProto.convert(ToProto.convert(flit).build) should equal (flit)
+ }
+
+ it should "support all Primops" in {
+ val builtInOps = PrimOps.listing.map(PrimOps.fromString(_))
+ for (op <- builtInOps) {
+ val expr = DoPrim(op, List.empty, List.empty, ir.UnknownType)
+ FromProto.convert(ToProto.convert(expr).build) should equal (expr)
+ }
+ }
+
+ it should "support all ExtModule features (except info which isn't yet supported by Chisel)" in {
+ val ports = Seq(
+ Port(ir.NoInfo, "port1", ir.Input, ir.UIntType(ir.IntWidth(8))),
+ Port(ir.NoInfo, "port2", ir.Output, ir.SIntType(ir.IntWidth(8)))
+ )
+ val params = Seq(
+ IntParam("param1", BigInt(Long.MinValue)),
+ DoubleParam("param2", Double.NegativeInfinity),
+ StringParam("param3", ir.StringLit("quite the string!")),
+ RawStringParam("param4", "get some raw strings")
+ )
+ val ext = ir.ExtModule(ir.NoInfo, "MyModule", ports, "DefNameHere", params)
+ FromProto.convert(ToProto.convert(ext).build) should equal (ext)
+ }
+
+ it should "supported FixedType" in {
+ val ftpe = ir.FixedType(IntWidth(8), IntWidth(4))
+ FromProto.convert(ToProto.convert(ftpe).build) should equal (ftpe)
+ }
+
+ it should "supported FixedLiteral" in {
+ val flit = ir.FixedLiteral(3, IntWidth(8), IntWidth(4))
+ FromProto.convert(ToProto.convert(flit).build) should equal (flit)
+ }
+
+ it should "support Analog and Attach" in {
+ val analog = ir.AnalogType(IntWidth(8))
+ FromProto.convert(ToProto.convert(analog).build) should equal (analog)
+
+ val attach = ir.Attach(ir.NoInfo, Seq(Reference("hi", ir.UnknownType)))
+ FromProto.convert(ToProto.convert(attach).head.build) should equal (attach)
+ }
+
+ // Regression tests were generated before Chisel could emit else
+ it should "support whens with elses" in {
+ val expr = Reference("hi", ir.UnknownType)
+ val stmt = Connect(ir.NoInfo, expr, expr)
+ val when = ir.Conditionally(ir.NoInfo, expr, stmt, stmt)
+ FromProto.convert(ToProto.convert(when).head.build) should equal (when)
+ }
+
+ it should "support SIntLiteral with a width" in {
+ val slit = ir.SIntLiteral(-123)
+ FromProto.convert(ToProto.convert(slit).build) should equal (slit)
+ }
+}
diff --git a/test/integration/GCDTester.pb b/test/integration/GCDTester.pb
new file mode 100644
index 00000000..fc7c2ba4
--- /dev/null
+++ b/test/integration/GCDTester.pb
Binary files differ