aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Koenig2019-04-22 13:46:37 -0700
committerGitHub2019-04-22 13:46:37 -0700
commit99ae1d6649f1731c5dec2098b10733735232b72c (patch)
tree04e7b0f4515fc9f79aa5f0d80aff2bb5805637c9
parentbf66997b1a2438a322cd619ca2b6aeb0f0ac0ba0 (diff)
Change Memory Depth to a BigInt (#1075)
-rw-r--r--src/main/proto/firrtl.proto15
-rw-r--r--src/main/scala/firrtl/Emitter.scala33
-rw-r--r--src/main/scala/firrtl/Visitor.scala38
-rw-r--r--src/main/scala/firrtl/WIR.scala2
-rw-r--r--src/main/scala/firrtl/ir/IR.scala2
-rw-r--r--src/main/scala/firrtl/passes/memlib/MemConf.scala4
-rw-r--r--src/main/scala/firrtl/passes/memlib/MemIR.scala2
-rw-r--r--src/main/scala/firrtl/proto/FromProto.scala21
-rw-r--r--src/main/scala/firrtl/proto/ToProto.scala10
-rw-r--r--src/test/scala/firrtlTests/MemSpec.scala68
-rw-r--r--src/test/scala/firrtlTests/ProtoBufSpec.scala45
11 files changed, 201 insertions, 39 deletions
diff --git a/src/main/proto/firrtl.proto b/src/main/proto/firrtl.proto
index 8f115c5e..2552b989 100644
--- a/src/main/proto/firrtl.proto
+++ b/src/main/proto/firrtl.proto
@@ -110,7 +110,10 @@ message Firrtl {
// Required.
Type type = 2;
// Required.
- uint32 depth = 3;
+ oneof depth {
+ uint32 uint_depth = 3;
+ BigInt bigint_depth = 9;
+ }
// Required.
uint32 write_latency = 4;
// Required.
@@ -121,10 +124,18 @@ message Firrtl {
}
message CMemory {
+ // As alternative to using VectorType as type
+ message TypeAndDepth {
+ Type data_type = 1;
+ BigInt depth = 2;
+ }
// Required.
string id = 1;
// Required.
- Type.VectorType type = 2;
+ oneof type {
+ Type.VectorType vector_type = 2;
+ TypeAndDepth type_and_depth = 4;
+ }
// Required.
bool sync_read = 3;
}
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index edbe9df6..7204eea6 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -419,6 +419,8 @@ class VerilogEmitter extends SeqTransform with Emitter {
// An alternative approach is to have one always block per combination of clock and async reset,
// but Formality doesn't allow more than 1 statement inside async reset always blocks
val asyncResetAlwaysBlocks = mutable.ArrayBuffer[(Expression, Expression, Seq[Any])]()
+ // Used to determine type of initvar for initializing memories
+ var maxMemSize: BigInt = BigInt(0)
val initials = ArrayBuffer[Seq[Any]]()
// In Verilog, async reset registers are expressed using always blocks of the form:
// always @(posedge clock or posedge reset) begin
@@ -432,11 +434,18 @@ class VerilogEmitter extends SeqTransform with Emitter {
val asyncInitials = ArrayBuffer[Seq[Any]]()
val simulates = ArrayBuffer[Seq[Any]]()
+ def bigIntToVLit(bi: BigInt): String =
+ if (bi.isValidInt) bi.toString else s"${bi.bitLength}'d$bi"
+
+ def declareVectorType(b: String, n: String, tpe: Type, size: BigInt, info: Info) = {
+ declares += Seq(b, " ", tpe, " ", n, " [0:", bigIntToVLit(size - 1), "];", info)
+ }
+
def declare(b: String, n: String, t: Type, info: Info) = t match {
case tx: VectorType =>
- declares += Seq(b, " ", tx.tpe, " ", n, " [0:", tx.size - 1, "];", info)
+ declareVectorType(b, n, tx.tpe, tx.size, info)
case tx =>
- declares += Seq(b, " ", tx, " ", n, ";", info)
+ declares += Seq(b, " ", tx, " ", n,";",info)
}
def assign(e: Expression, value: Expression, info: Info) {
@@ -533,10 +542,13 @@ class VerilogEmitter extends SeqTransform with Emitter {
}
def initialize_mem(s: DefMemory) {
+ if (s.depth > maxMemSize) {
+ maxMemSize = s.depth
+ }
val index = wref("initvar", s.dataType)
val rstring = rand_string(s.dataType)
initials += Seq("`ifdef RANDOMIZE_MEM_INIT")
- initials += Seq("for (initvar = 0; initvar < ", s.depth, "; initvar = initvar+1)")
+ initials += Seq("for (initvar = 0; initvar < ", bigIntToVLit(s.depth), "; initvar = initvar+1)")
initials += Seq(tab, WSubAccess(wref(s.name, s.dataType), index, s.dataType, FEMALE),
" = ", rstring, ";")
initials += Seq("`endif // RANDOMIZE_MEM_INIT")
@@ -687,7 +699,7 @@ class VerilogEmitter extends SeqTransform with Emitter {
case GroundType(IntWidth(width)) => width
})
val decl = if (fullSize > (1 << 29)) "reg /* sparse */" else "reg"
- declare(decl, sx.name, VectorType(sx.dataType, sx.depth), sx.info)
+ declareVectorType(decl, sx.name, sx.dataType, sx.depth, sx.info)
initialize_mem(sx)
if (sx.readLatency != 0 || sx.writeLatency != 1)
throw EmitterException("All memories should be transformed into " +
@@ -708,7 +720,7 @@ class VerilogEmitter extends SeqTransform with Emitter {
// assign(en, netlist(en)) //;Connects value to m.r.en
val mem = WRef(sx.name, memType(sx), MemKind, UNKNOWNGENDER)
val memPort = WSubAccess(mem, addr, sx.dataType, UNKNOWNGENDER)
- val depthValue = UIntLiteral(sx.depth, IntWidth(BigInt(sx.depth).bitLength))
+ val depthValue = UIntLiteral(sx.depth, IntWidth(sx.depth.bitLength))
val garbageGuard = DoPrim(Geq, Seq(addr, depthValue), Seq(), UnknownType)
if ((sx.depth & (sx.depth - 1)) == 0)
@@ -788,7 +800,16 @@ class VerilogEmitter extends SeqTransform with Emitter {
emit(Seq("`define RANDOM $random"))
emit(Seq("`endif"))
emit(Seq("`ifdef RANDOMIZE_MEM_INIT"))
- emit(Seq(" integer initvar;"))
+ // Since simulators don't actually support memories larger than 2^31 - 1, there is no reason
+ // to change Verilog emission in the common case. Instead, we only emit a larger initvar
+ // where necessary
+ if (maxMemSize.isValidInt) {
+ emit(Seq(" integer initvar;"))
+ } else {
+ // Width must be able to represent maxMemSize because that's the upper bound in init loop
+ val width = maxMemSize.bitLength - 1 // minus one because [width-1:0] has a width of "width"
+ emit(Seq(s" reg [$width:0] initvar;"))
+ }
emit(Seq("`endif"))
emit(Seq("initial begin"))
emit(Seq(" `ifdef RANDOMIZE"))
diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala
index 91dfaae9..9914de70 100644
--- a/src/main/scala/firrtl/Visitor.scala
+++ b/src/main/scala/firrtl/Visitor.scala
@@ -139,6 +139,19 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] {
}
}
+ // Special case "type" of CHIRRTL mems because their size can be BigInt
+ private def visitCMemType(ctx: TypeContext): (Type, BigInt) = {
+ def loc: String = s"${ctx.getStart.getLine}:${ctx.getStart.getCharPositionInLine}"
+ ctx.getChild(0) match {
+ case typeContext: TypeContext =>
+ val tpe = visitType(ctx.`type`)
+ val size = string2BigInt(ctx.intLit(0).getText)
+ (tpe, size)
+ case _ =>
+ throw new ParserException(s"[$loc] Must provide cmem or smem with vector type, got ${ctx.getText}")
+ }
+ }
+
private def visitField[FirrtlNode](ctx: FieldContext): Field = {
val flip = if (ctx.getChild(0).getText == "flip") Flip else Default
Field(ctx.fieldId.getText, flip, visitType(ctx.`type`))
@@ -156,7 +169,7 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] {
val readers = mutable.ArrayBuffer.empty[String]
val writers = mutable.ArrayBuffer.empty[String]
val readwriters = mutable.ArrayBuffer.empty[String]
- case class ParamValue(typ: Option[Type] = None, lit: Option[Int] = None, ruw: Option[String] = None, unique: Boolean = true)
+ case class ParamValue(typ: Option[Type] = None, lit: Option[BigInt] = None, ruw: Option[String] = None, unique: Boolean = true)
val fieldMap = mutable.HashMap[String, ParamValue]()
def parseMemFields(memFields: Seq[MemFieldContext]): Unit =
@@ -171,7 +184,7 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] {
val paramDef = fieldName match {
case "data-type" => ParamValue(typ = Some(visitType(field.`type`())))
case "read-under-write" => ParamValue(ruw = Some(field.ruw().getText)) // TODO
- case _ => ParamValue(lit = Some(field.intLit().getText.toInt))
+ case _ => ParamValue(lit = Some(BigInt(field.intLit().getText)))
}
if (fieldMap.contains(fieldName))
throw new ParameterRedefinedException(s"Redefinition of $fieldName in FIRRTL line:${field.start.getLine}")
@@ -201,7 +214,8 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] {
DefMemory(info,
name = ctx.id(0).getText, dataType = fieldMap("data-type").typ.get,
depth = lit("depth"),
- writeLatency = lit("write-latency"), readLatency = lit("read-latency"),
+ writeLatency = lit("write-latency").toInt,
+ readLatency = lit("read-latency").toInt,
readers = readers, writers = writers, readwriters = readwriters,
readUnderWrite = ruw
)
@@ -250,21 +264,11 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] {
DefRegister(info, name, tpe, visitExp(ctx_exp(0)), reset, init)
case "mem" => visitMem(ctx)
case "cmem" =>
- val t = visitType(ctx.`type`())
- t match {
- case (t: VectorType) => CDefMemory(info, ctx.id(0).getText, t.tpe, t.size, seq = false)
- case _ => throw new ParserException(s"${
- info
- }: Must provide cmem with vector type")
- }
+ val (tpe, size) = visitCMemType(ctx.`type`())
+ CDefMemory(info, ctx.id(0).getText, tpe, size, seq = false)
case "smem" =>
- val t = visitType(ctx.`type`())
- t match {
- case (t: VectorType) => CDefMemory(info, ctx.id(0).getText, t.tpe, t.size, seq = true)
- case _ => throw new ParserException(s"${
- info
- }: Must provide cmem with vector type")
- }
+ val (tpe, size) = visitCMemType(ctx.`type`())
+ CDefMemory(info, ctx.id(0).getText, tpe, size, seq = true)
case "inst" => DefInstance(info, ctx.id(0).getText, ctx.id(1).getText)
case "node" => DefNode(info, ctx.id(0).getText, visitExp(ctx_exp(0)))
diff --git a/src/main/scala/firrtl/WIR.scala b/src/main/scala/firrtl/WIR.scala
index 0ec37d34..cc2d87e7 100644
--- a/src/main/scala/firrtl/WIR.scala
+++ b/src/main/scala/firrtl/WIR.scala
@@ -313,7 +313,7 @@ case class CDefMemory(
info: Info,
name: String,
tpe: Type,
- size: Int,
+ size: BigInt,
seq: Boolean) extends Statement with HasInfo {
def serialize: String = (if (seq) "smem" else "cmem") +
s" $name : ${tpe.serialize} [$size]" + info.serialize
diff --git a/src/main/scala/firrtl/ir/IR.scala b/src/main/scala/firrtl/ir/IR.scala
index 4c00bdd1..8124e1e6 100644
--- a/src/main/scala/firrtl/ir/IR.scala
+++ b/src/main/scala/firrtl/ir/IR.scala
@@ -289,7 +289,7 @@ case class DefMemory(
info: Info,
name: String,
dataType: Type,
- depth: Int,
+ depth: BigInt,
writeLatency: Int,
readLatency: Int,
readers: Seq[String],
diff --git a/src/main/scala/firrtl/passes/memlib/MemConf.scala b/src/main/scala/firrtl/passes/memlib/MemConf.scala
index e53a5de7..18fcbf37 100644
--- a/src/main/scala/firrtl/passes/memlib/MemConf.scala
+++ b/src/main/scala/firrtl/passes/memlib/MemConf.scala
@@ -29,7 +29,7 @@ object MemPort {
case class MemConf(
name: String,
- depth: Int,
+ depth: BigInt,
width: Int,
ports: Map[MemPort, Int],
maskGranularity: Option[Int]
@@ -57,7 +57,7 @@ object MemConf {
}).flatten
}
- def apply(name: String, depth: Int, width: Int, readPorts: Int, writePorts: Int, readWritePorts: Int, maskGranularity: Option[Int]): MemConf = {
+ def apply(name: String, depth: BigInt, width: Int, readPorts: Int, writePorts: Int, readWritePorts: Int, maskGranularity: Option[Int]): MemConf = {
val ports: Map[MemPort, Int] = (if (maskGranularity.isEmpty) {
(if (writePorts == 0) Map.empty[MemPort, Int] else Map(WritePort -> writePorts)) ++
(if (readWritePorts == 0) Map.empty[MemPort, Int] else Map(ReadWritePort -> readWritePorts))
diff --git a/src/main/scala/firrtl/passes/memlib/MemIR.scala b/src/main/scala/firrtl/passes/memlib/MemIR.scala
index 55f0f571..41691a0a 100644
--- a/src/main/scala/firrtl/passes/memlib/MemIR.scala
+++ b/src/main/scala/firrtl/passes/memlib/MemIR.scala
@@ -30,7 +30,7 @@ case class DefAnnotatedMemory(
info: Info,
name: String,
dataType: Type,
- depth: Int,
+ depth: BigInt,
writeLatency: Int,
readLatency: Int,
readers: Seq[String],
diff --git a/src/main/scala/firrtl/proto/FromProto.scala b/src/main/scala/firrtl/proto/FromProto.scala
index e7d415cb..44e505f1 100644
--- a/src/main/scala/firrtl/proto/FromProto.scala
+++ b/src/main/scala/firrtl/proto/FromProto.scala
@@ -133,9 +133,19 @@ object FromProto {
ir.Conditionally(convert(info), convert(when.getPredicate), conseq, alt)
}
+ def convert(dt: Firrtl.Statement.CMemory.TypeAndDepth): (ir.Type, BigInt) =
+ (convert(dt.getDataType), convert(dt.getDepth))
+
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.CMemory._
+ val (tpe, depth) = cmem.getTypeCase.getNumber match {
+ case VECTOR_TYPE_FIELD_NUMBER =>
+ val vtpe = convert(cmem.getVectorType)
+ (vtpe.tpe, BigInt(vtpe.size))
+ case TYPE_AND_DEPTH_FIELD_NUMBER =>
+ convert(cmem.getTypeAndDepth)
+ }
+ CDefMemory(convert(info), cmem.getId, tpe, depth, cmem.getSyncRead)
}
import Firrtl.Statement.MemoryPort.Direction._
@@ -165,7 +175,12 @@ object FromProto {
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,
+ import Firrtl.Statement.Memory._
+ val depth = mem.getDepthCase.getNumber match {
+ case UINT_DEPTH_FIELD_NUMBER => BigInt(mem.getUintDepth)
+ case BIGINT_DEPTH_FIELD_NUMBER => convert(mem.getBigintDepth)
+ }
+ ir.DefMemory(convert(info), mem.getId, dtype, depth, mem.getWriteLatency, mem.getReadLatency,
rs, ws, rws, None)
}
diff --git a/src/main/scala/firrtl/proto/ToProto.scala b/src/main/scala/firrtl/proto/ToProto.scala
index b0b59e06..8681e8f2 100644
--- a/src/main/scala/firrtl/proto/ToProto.scala
+++ b/src/main/scala/firrtl/proto/ToProto.scala
@@ -190,6 +190,11 @@ object ToProto {
}
}
+ def convert(tpe: ir.Type, depth: BigInt): Firrtl.Statement.CMemory.TypeAndDepth.Builder =
+ Firrtl.Statement.CMemory.TypeAndDepth.newBuilder()
+ .setDataType(convert(tpe))
+ .setDepth(convertToBigInt(depth))
+
def convert(stmt: ir.Statement): Seq[Firrtl.Statement.Builder] = {
stmt match {
case ir.Block(stmts) => stmts.flatMap(convert(_))
@@ -259,7 +264,7 @@ object ToProto {
val mem = Firrtl.Statement.Memory.newBuilder()
.setId(name)
.setType(convert(dtype))
- .setDepth(depth)
+ .setBigintDepth(convertToBigInt(depth))
.setWriteLatency(wlat)
.setReadLatency(rlat)
mem.addAllReaderId(rs.asJava)
@@ -267,10 +272,9 @@ object ToProto {
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)
+ .setTypeAndDepth(convert(tpe, size))
.setSyncRead(seq)
sb.setCmemory(mb)
case CDefMPort(_, name, _, mem, exprs, dir) =>
diff --git a/src/test/scala/firrtlTests/MemSpec.scala b/src/test/scala/firrtlTests/MemSpec.scala
index 67b7e74d..612a952d 100644
--- a/src/test/scala/firrtlTests/MemSpec.scala
+++ b/src/test/scala/firrtlTests/MemSpec.scala
@@ -2,7 +2,10 @@
package firrtlTests
-class MemSpec extends FirrtlPropSpec {
+import firrtl._
+import FirrtlCheckers._
+
+class MemSpec extends FirrtlPropSpec with FirrtlMatchers {
property("Zero-ported mems should be supported!") {
runFirrtlTest("ZeroPortMem", "/features")
@@ -11,5 +14,68 @@ class MemSpec extends FirrtlPropSpec {
property("Mems with zero-width elements should be supported!") {
runFirrtlTest("ZeroWidthMem", "/features")
}
+
+ property("Very large memories should be supported") {
+ val addrWidth = 65
+ val memSize = BigInt(1) << addrWidth
+ val input =
+ s"""
+ |circuit Test :
+ | module Test :
+ | input clock : Clock
+ | input raddr : UInt<$addrWidth>
+ | output rdata : UInt<8>
+ | input wdata : UInt<8>
+ | input waddr : UInt<$addrWidth>
+ | input wen : UInt<1>
+ |
+ | mem m :
+ | data-type => UInt<8>
+ | depth => $memSize
+ | reader => r
+ | writer => w
+ | read-latency => 1
+ | write-latency => 1
+ | read-under-write => undefined
+ | rdata <= m.r.data
+ | m.r.addr <= raddr
+ | m.r.en <= UInt(1)
+ | m.r.clk <= clock
+ | m.w.addr <= waddr
+ | m.w.data <= wdata
+ | m.w.en <= wen
+ | m.w.clk <= clock
+ | m.w.mask <= UInt(1)
+ """.stripMargin
+ val result = (new VerilogCompiler).compileAndEmit(CircuitState(parse(input), ChirrtlForm, List.empty))
+ // TODO Not great that it includes the sparse comment for VCS
+ result should containLine (s"reg /* sparse */ [7:0] m [0:$addrWidth'd${memSize-1}];")
+ }
+
+ property("Very large CHIRRTL memories should be supported") {
+ val addrWidth = 65
+ val memSize = BigInt(1) << addrWidth
+ val input =
+ s"""
+ |circuit Test :
+ | module Test :
+ | input clock : Clock
+ | input raddr : UInt<$addrWidth>
+ | output rdata : UInt<8>
+ | input wdata : UInt<8>
+ | input waddr : UInt<$addrWidth>
+ | input wen : UInt<1>
+ |
+ | cmem m : UInt<8>[$memSize]
+ | read mport r = m[raddr], clock
+ | rdata <= r
+ | write mport w = m[waddr], clock
+ | when wen :
+ | w <= wdata
+ """.stripMargin
+ val result = (new VerilogCompiler).compileAndEmit(CircuitState(parse(input), ChirrtlForm, List.empty))
+ // TODO Not great that it includes the sparse comment for VCS
+ result should containLine (s"reg /* sparse */ [7:0] m [0:$addrWidth'd${memSize-1}];")
+ }
}
diff --git a/src/test/scala/firrtlTests/ProtoBufSpec.scala b/src/test/scala/firrtlTests/ProtoBufSpec.scala
index 090a7fea..7a0c3eeb 100644
--- a/src/test/scala/firrtlTests/ProtoBufSpec.scala
+++ b/src/test/scala/firrtlTests/ProtoBufSpec.scala
@@ -107,12 +107,12 @@ class ProtoBufSpec extends FirrtlFlatSpec {
FromProto.convert(ToProto.convert(ext).build) should equal (ext)
}
- it should "supported FixedType" in {
+ it should "support FixedType" in {
val ftpe = ir.FixedType(IntWidth(8), IntWidth(4))
FromProto.convert(ToProto.convert(ftpe).build) should equal (ftpe)
}
- it should "supported FixedLiteral" in {
+ it should "support FixedLiteral" in {
val flit = ir.FixedLiteral(3, IntWidth(8), IntWidth(4))
FromProto.convert(ToProto.convert(flit).build) should equal (flit)
}
@@ -138,6 +138,47 @@ class ProtoBufSpec extends FirrtlFlatSpec {
FromProto.convert(ToProto.convert(slit).build) should equal (slit)
}
+ // Backwards compatibility
+ it should "support mems using old uint32 and new BigInt" in {
+ val size = 128
+ val mem = DefMemory(NoInfo, "m", UIntType(IntWidth(8)), size, 1, 1, List("r"), List("w"), List("rw"))
+ val builder = ToProto.convert(mem).head
+ val defaultProto = builder.build()
+ val oldProto = Firrtl.Statement.newBuilder().setMemory(
+ builder.getMemoryBuilder.clearDepth().setUintDepth(size)
+ ).build()
+ // These Proto messages are not the same
+ defaultProto shouldNot equal (oldProto)
+
+ val defaultMem = FromProto.convert(defaultProto)
+ val oldMem = FromProto.convert(oldProto)
+
+ // But they both deserialize to the original!
+ defaultMem should equal (mem)
+ oldMem should equal (mem)
+ }
+
+ // Backwards compatibility
+ it should "support cmems using old VectorType and new TypeAndDepth" in {
+ val size = 128
+ val cmem = CDefMemory(NoInfo, "m", UIntType(IntWidth(8)), size, true)
+ val vtpe = ToProto.convert(VectorType(UIntType(IntWidth(8)), size))
+ val builder = ToProto.convert(cmem).head
+ val defaultProto = builder.build()
+ val oldProto = Firrtl.Statement.newBuilder().setCmemory(
+ builder.getCmemoryBuilder.clearTypeAndDepth().setVectorType(vtpe)
+ ).build()
+ // These Proto messages are not the same
+ defaultProto shouldNot equal (oldProto)
+
+ val defaultCMem = FromProto.convert(defaultProto)
+ val oldCMem = FromProto.convert(oldProto)
+
+ // But they both deserialize to the original!
+ defaultCMem should equal (cmem)
+ oldCMem should equal (cmem)
+ }
+
it should "support AsyncResetTypes" in {
val port = ir.Port(ir.NoInfo, "reset", ir.Input, ir.AsyncResetType)
FromProto.convert(ToProto.convert(port).build) should equal (port)