aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/ir
diff options
context:
space:
mode:
authorKevin Laeufer2021-02-17 12:16:52 -0800
committerGitHub2021-02-17 20:16:52 +0000
commit5a89fca6090948d0a99c217a09c692e58a20d1df (patch)
tree7996829e3589205607862cbbf578a4e9a9d6e623 /src/main/scala/firrtl/ir
parent856226416cfa2d770c7205efad5331297c2e3a32 (diff)
Allow Side Effecting Statement to have Names (#2057)
* firrtl: add optional statement labels for stop, printf, assert, assume and cover * test: parsing of statement labels * ir: ensure that name is properly retained * SymbolTable: add support for labled statements * test: parsing statement labels * test: lower types name collisions with named statements * ignore empty names * Inline: deal with named and unnamed statements * RemoveWires: treat stop, printf and verification statements as "others" * test: fix InlineInstance tests * DeadCodeEliminations: statements are now als declarations * CheckHighForm: ensure that statement names are not used as references * CheckSpec: throw error if statement name collides * add pass to automatically add missing statement names * check: make sure that two statements cannot have the same name * stmtLabel -> stmtName * scalafmt * add statement names to spec * spec: meta data -> metadata * EnsureStatementNames: explain naming algorithm * remove returns * better namespace use * ir: add CanBeReferenced trait * ir: add newline as jack requested
Diffstat (limited to 'src/main/scala/firrtl/ir')
-rw-r--r--src/main/scala/firrtl/ir/IR.scala56
-rw-r--r--src/main/scala/firrtl/ir/Serializer.scala18
2 files changed, 52 insertions, 22 deletions
diff --git a/src/main/scala/firrtl/ir/IR.scala b/src/main/scala/firrtl/ir/IR.scala
index 1b564d42..9c3d6186 100644
--- a/src/main/scala/firrtl/ir/IR.scala
+++ b/src/main/scala/firrtl/ir/IR.scala
@@ -4,7 +4,7 @@ package firrtl
package ir
import Utils.{dec2string, trim}
-import dataclass.data
+import dataclass.{data, since}
import firrtl.constraint.{Constraint, IsKnown, IsVar}
import org.apache.commons.text.translate.{AggregateTranslator, JavaUnicodeEscaper, LookupTranslator}
@@ -227,6 +227,13 @@ abstract class Expression extends FirrtlNode {
*/
sealed trait RefLikeExpression extends Expression { def flow: Flow }
+/** Represents a statement that can be referenced in a firrtl expression.
+ * This explicitly excludes named side-effecting statements like Print, Stop and Verification.
+ * Note: This trait cannot be sealed since the memory ports are declared in WIR.scala.
+ * Once we fully remove all WIR, this trait could be sealed.
+ */
+trait CanBeReferenced
+
object Reference {
/** Creates a Reference from a Wire */
@@ -387,7 +394,11 @@ abstract class Statement extends FirrtlNode {
def foreachString(f: String => Unit): Unit
def foreachInfo(f: Info => Unit): Unit
}
-case class DefWire(info: Info, name: String, tpe: Type) extends Statement with IsDeclaration with UseSerializer {
+case class DefWire(info: Info, name: String, tpe: Type)
+ extends Statement
+ with IsDeclaration
+ with CanBeReferenced
+ with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement = this
def mapType(f: Type => Type): Statement = DefWire(info, name, f(tpe))
@@ -408,6 +419,7 @@ case class DefRegister(
init: Expression)
extends Statement
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement =
@@ -429,6 +441,7 @@ object DefInstance {
case class DefInstance(info: Info, name: String, module: String, tpe: Type = UnknownType)
extends Statement
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapExpr(f: Expression => Expression): Statement = this
def mapStmt(f: Statement => Statement): Statement = this
@@ -462,6 +475,7 @@ case class DefMemory(
readUnderWrite: ReadUnderWrite.Value = ReadUnderWrite.Undefined)
extends Statement
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement = this
@@ -477,6 +491,7 @@ case class DefMemory(
case class DefNode(info: Info, name: String, value: Expression)
extends Statement
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement = DefNode(info, name, f(value))
@@ -594,22 +609,24 @@ case class Attach(info: Info, exprs: Seq[Expression]) extends Statement with Has
def foreachString(f: String => Unit): Unit = ()
def foreachInfo(f: Info => Unit): Unit = f(info)
}
-@data class Stop(info: Info, ret: Int, clk: Expression, en: Expression)
+
+@data class Stop(info: Info, ret: Int, clk: Expression, en: Expression, @since("FIRRTL 1.5") name: String = "")
extends Statement
with HasInfo
+ with IsDeclaration
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
- def mapExpr(f: Expression => Expression): Statement = Stop(info, ret, f(clk), f(en))
+ def mapExpr(f: Expression => Expression): Statement = Stop(info, ret, f(clk), f(en), name)
def mapType(f: Type => Type): Statement = this
- def mapString(f: String => String): Statement = this
+ def mapString(f: String => String): Statement = withName(f(name))
def mapInfo(f: Info => Info): Statement = this.copy(info = f(info))
def foreachStmt(f: Statement => Unit): Unit = ()
def foreachExpr(f: Expression => Unit): Unit = { f(clk); f(en) }
def foreachType(f: Type => Unit): Unit = ()
- def foreachString(f: String => Unit): Unit = ()
+ def foreachString(f: String => Unit): Unit = f(name)
def foreachInfo(f: Info => Unit): Unit = f(info)
def copy(info: Info = info, ret: Int = ret, clk: Expression = clk, en: Expression = en): Stop = {
- Stop(info, ret, clk, en)
+ Stop(info, ret, clk, en, name)
}
}
object Stop {
@@ -622,19 +639,22 @@ object Stop {
string: StringLit,
args: Seq[Expression],
clk: Expression,
- en: Expression)
+ en: Expression,
+ @since("FIRRTL 1.5")
+ name: String = "")
extends Statement
with HasInfo
+ with IsDeclaration
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
- def mapExpr(f: Expression => Expression): Statement = Print(info, string, args.map(f), f(clk), f(en))
+ def mapExpr(f: Expression => Expression): Statement = Print(info, string, args.map(f), f(clk), f(en), name)
def mapType(f: Type => Type): Statement = this
- def mapString(f: String => String): Statement = this
+ def mapString(f: String => String): Statement = withName(f(name))
def mapInfo(f: Info => Info): Statement = this.copy(info = f(info))
def foreachStmt(f: Statement => Unit): Unit = ()
def foreachExpr(f: Expression => Unit): Unit = { args.foreach(f); f(clk); f(en) }
def foreachType(f: Type => Unit): Unit = ()
- def foreachString(f: String => Unit): Unit = ()
+ def foreachString(f: String => Unit): Unit = f(name)
def foreachInfo(f: Info => Unit): Unit = f(info)
def copy(
info: Info = info,
@@ -643,7 +663,7 @@ object Stop {
clk: Expression = clk,
en: Expression = en
): Print = {
- Print(info, string, args, clk, en)
+ Print(info, string, args, clk, en, name)
}
}
object Print {
@@ -665,20 +685,23 @@ object Formal extends Enumeration {
clk: Expression,
pred: Expression,
en: Expression,
- msg: StringLit)
+ msg: StringLit,
+ @since("FIRRTL 1.5")
+ name: String = "")
extends Statement
with HasInfo
+ with IsDeclaration
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement =
copy(clk = f(clk), pred = f(pred), en = f(en))
def mapType(f: Type => Type): Statement = this
- def mapString(f: String => String): Statement = this
+ def mapString(f: String => String): Statement = withName(f(name))
def mapInfo(f: Info => Info): Statement = copy(info = f(info))
def foreachStmt(f: Statement => Unit): Unit = ()
def foreachExpr(f: Expression => Unit): Unit = { f(clk); f(pred); f(en); }
def foreachType(f: Type => Unit): Unit = ()
- def foreachString(f: String => Unit): Unit = ()
+ def foreachString(f: String => Unit): Unit = f(name)
def foreachInfo(f: Info => Unit): Unit = f(info)
def copy(
op: Formal.Value = op,
@@ -688,7 +711,7 @@ object Formal extends Enumeration {
en: Expression = en,
msg: StringLit = msg
): Verification = {
- Verification(op, info, clk, pred, en, msg)
+ Verification(op, info, clk, pred, en, msg, name)
}
}
object Verification {
@@ -1016,6 +1039,7 @@ case class Port(
tpe: Type)
extends FirrtlNode
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapType(f: Type => Type): Port = Port(info, name, direction, f(tpe))
def mapString(f: String => String): Port = Port(info, f(name), direction, tpe)
diff --git a/src/main/scala/firrtl/ir/Serializer.scala b/src/main/scala/firrtl/ir/Serializer.scala
index 983a7866..caea0a9c 100644
--- a/src/main/scala/firrtl/ir/Serializer.scala
+++ b/src/main/scala/firrtl/ir/Serializer.scala
@@ -102,11 +102,13 @@ object Serializer {
s(it.next())
if (it.hasNext) newLineAndIndent()
}
- case Stop(info, ret, clk, en) =>
- b ++= "stop("; s(clk); b ++= ", "; s(en); b ++= ", "; b ++= ret.toString; b += ')'; s(info)
- case Print(info, string, args, clk, en) =>
+ case stop @ Stop(info, ret, clk, en) =>
+ b ++= "stop("; s(clk); b ++= ", "; s(en); b ++= ", "; b ++= ret.toString; b += ')'
+ sStmtName(stop.name); s(info)
+ case print @ Print(info, string, args, clk, en) =>
b ++= "printf("; s(clk); b ++= ", "; s(en); b ++= ", "; b ++= string.escape
- if (args.nonEmpty) b ++= ", "; s(args, ", "); b += ')'; s(info)
+ if (args.nonEmpty) b ++= ", "; s(args, ", "); b += ')'
+ sStmtName(print.name); s(info)
case IsInvalid(info, expr) => s(expr); b ++= " is invalid"; s(info)
case DefWire(info, name, tpe) => b ++= "wire "; b ++= name; b ++= " : "; s(tpe); s(info)
case DefRegister(info, name, tpe, clock, reset, init) =>
@@ -138,9 +140,9 @@ object Serializer {
case Attach(info, exprs) =>
// exprs should never be empty since the attach statement takes *at least* two signals according to the spec
b ++= "attach ("; s(exprs, ", "); b += ')'; s(info)
- case Verification(op, info, clk, pred, en, msg) =>
+ case veri @ Verification(op, info, clk, pred, en, msg) =>
b ++= op.toString; b += '('; s(List(clk, pred, en), ", ", false); b ++= msg.escape
- b += ')'; s(info)
+ b += ')'; sStmtName(veri.name); s(info)
// WIR
case firrtl.CDefMemory(info, name, tpe, size, seq, readUnderWrite) =>
@@ -155,6 +157,10 @@ object Serializer {
case other => b ++= other.serialize // Handle user-defined nodes
}
+ private def sStmtName(lbl: String)(implicit b: StringBuilder): Unit = {
+ if (lbl.nonEmpty) { b ++= s" : $lbl" }
+ }
+
private def s(node: Width)(implicit b: StringBuilder, indent: Int): Unit = node match {
case IntWidth(width) => b += '<'; b ++= width.toString(); b += '>'
case UnknownWidth => // empty string