aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/scala/firrtl/passes/CheckHighForm.scala53
-rw-r--r--src/test/resources/features/ChirrtlMems.fir6
-rw-r--r--src/test/scala/firrtlTests/CheckSpec.scala47
-rw-r--r--test/integration/RightShiftTester.fir2
4 files changed, 91 insertions, 17 deletions
diff --git a/src/main/scala/firrtl/passes/CheckHighForm.scala b/src/main/scala/firrtl/passes/CheckHighForm.scala
index 889cdae2..512602cf 100644
--- a/src/main/scala/firrtl/passes/CheckHighForm.scala
+++ b/src/main/scala/firrtl/passes/CheckHighForm.scala
@@ -12,6 +12,25 @@ import firrtl.options.Dependency
trait CheckHighFormLike { this: Pass =>
type NameSet = collection.mutable.HashSet[String]
+ private object ScopeView {
+ def apply(): ScopeView = new ScopeView(new NameSet, List(new NameSet))
+ }
+
+ private class ScopeView private (moduleNS: NameSet, scopes: List[NameSet]) {
+ require(scopes.nonEmpty)
+ def declare(name: String): Unit = {
+ moduleNS += name
+ scopes.head += name
+ }
+ def expandMPortVisibility(port: CDefMPort): Unit = {
+ // Legacy CHIRRTL ports are visible in any scope where their parent memory is visible
+ scopes.find(_.contains(port.mem)).getOrElse(scopes.head) += port.name
+ }
+ def legalDecl(name: String): Boolean = !moduleNS.contains(name)
+ def legalRef(name: String): Boolean = scopes.exists(_.contains(name))
+ def childScope(): ScopeView = new ScopeView(moduleNS, new NameSet +: scopes)
+ }
+
// Custom Exceptions
class NotUniqueException(info: Info, mname: String, name: String) extends PassException(
s"$info: [module $mname] Reference $name does not have a unique name.")
@@ -176,11 +195,11 @@ trait CheckHighFormLike { this: Pass =>
}
}
- def checkHighFormE(info: Info, mname: String, names: NameSet)(e: Expression): Unit = {
+ def checkHighFormE(info: Info, mname: String, names: ScopeView)(e: Expression): Unit = {
e match {
- case ex: Reference if !names(ex.name) =>
+ case ex: Reference if !names.legalRef(ex.name) =>
errors.append(new UndeclaredReferenceException(info, mname, ex.name))
- case ex: WRef if !names(ex.name) =>
+ case ex: WRef if !names.legalRef(ex.name) =>
errors.append(new UndeclaredReferenceException(info, mname, ex.name))
case ex: UIntLiteral if ex.value < 0 =>
errors.append(new NegUIntException(info, mname))
@@ -194,10 +213,10 @@ trait CheckHighFormLike { this: Pass =>
e foreach checkHighFormE(info, mname, names)
}
- def checkName(info: Info, mname: String, names: NameSet)(name: String): Unit = {
- if (names(name))
+ def checkName(info: Info, mname: String, names: ScopeView)(name: String): Unit = {
+ if (!names.legalDecl(name))
errors.append(new NotUniqueException(info, mname, name))
- names += name
+ names.declare(name)
}
def checkInstance(info: Info, child: String, parent: String): Unit = {
@@ -209,7 +228,7 @@ trait CheckHighFormLike { this: Pass =>
errors.append(new InstanceLoop(info, parent, childToParent mkString "->"))
}
- def checkHighFormS(minfo: Info, mname: String, names: NameSet)(s: Statement): Unit = {
+ def checkHighFormS(minfo: Info, mname: String, names: ScopeView)(s: Statement): Unit = {
val info = get_info(s) match {case NoInfo => minfo case x => x}
s foreach checkName(info, mname, names)
s match {
@@ -228,18 +247,26 @@ trait CheckHighFormLike { this: Pass =>
case sx: Connect => checkValidLoc(info, mname, sx.loc)
case sx: PartialConnect => checkValidLoc(info, mname, sx.loc)
case sx: Print => checkFstring(info, mname, sx.string, sx.args.length)
- case _: CDefMemory | _: CDefMPort => errorOnChirrtl(info, mname, s).foreach { e => errors.append(e) }
+ case _: CDefMemory => errorOnChirrtl(info, mname, s).foreach { e => errors.append(e) }
+ case mport: CDefMPort =>
+ errorOnChirrtl(info, mname, s).foreach { e => errors.append(e) }
+ names.expandMPortVisibility(mport)
case sx => // Do Nothing
}
s foreach checkHighFormT(info, mname)
s foreach checkHighFormE(info, mname, names)
- s foreach checkHighFormS(minfo, mname, names)
+ s match {
+ case Conditionally(_,_, conseq, alt) =>
+ checkHighFormS(minfo, mname, names.childScope())(conseq)
+ checkHighFormS(minfo, mname, names.childScope())(alt)
+ case _ => s foreach checkHighFormS(minfo, mname, names)
+ }
}
- def checkHighFormP(mname: String, names: NameSet)(p: Port): Unit = {
- if (names(p.name))
+ def checkHighFormP(mname: String, names: ScopeView)(p: Port): Unit = {
+ if (!names.legalDecl(p.name))
errors.append(new NotUniqueException(NoInfo, mname, p.name))
- names += p.name
+ names.declare(p.name)
checkHighFormT(p.info, mname)(p.tpe)
}
@@ -255,7 +282,7 @@ trait CheckHighFormLike { this: Pass =>
}
def checkHighFormM(m: DefModule): Unit = {
- val names = new NameSet
+ val names = ScopeView()
m foreach checkHighFormP(m.name, names)
m foreach checkHighFormS(m.info, m.name, names)
m match {
diff --git a/src/test/resources/features/ChirrtlMems.fir b/src/test/resources/features/ChirrtlMems.fir
index c51e3b78..de5b3cf3 100644
--- a/src/test/resources/features/ChirrtlMems.fir
+++ b/src/test/resources/features/ChirrtlMems.fir
@@ -14,13 +14,13 @@ circuit ChirrtlMems :
raddr <= add(raddr, UInt(1))
infer mport r = ram[raddr], newClock
+ reg waddr : UInt<4>, clock with : (reset => (reset, UInt(0)))
+ waddr <= add(waddr, UInt(1))
+
when wen :
node newerClock = clock
- reg waddr : UInt<4>, clock with : (reset => (reset, UInt(0)))
- waddr <= add(waddr, UInt(1))
infer mport w = ram[waddr], newerClock
w <= waddr
-
when eq(waddr, UInt(0)) :
raddr <= UInt(0)
diff --git a/src/test/scala/firrtlTests/CheckSpec.scala b/src/test/scala/firrtlTests/CheckSpec.scala
index c622bde5..b49054ad 100644
--- a/src/test/scala/firrtlTests/CheckSpec.scala
+++ b/src/test/scala/firrtlTests/CheckSpec.scala
@@ -352,6 +352,53 @@ class CheckSpec extends AnyFlatSpec with Matchers {
}
}
+ "Conditionally statements" should "create a new scope" in {
+ val input =
+ s"""|circuit scopes:
+ | module scopes:
+ | input i: UInt<1>
+ | output o: UInt<1>
+ | when i:
+ | node x = not(i)
+ | o <= and(x, i)
+ |""".stripMargin
+ assertThrows[CheckHighForm.UndeclaredReferenceException] {
+ checkHighInput(input)
+ }
+ }
+
+ "Attempting to shadow a component name" should "throw an error" in {
+ val input =
+ s"""|circuit scopes:
+ | module scopes:
+ | input i: UInt<1>
+ | output o: UInt<1>
+ | wire x: UInt<1>
+ | when i:
+ | node x = not(i)
+ | o <= and(x, i)
+ |""".stripMargin
+ assertThrows[CheckHighForm.NotUniqueException] {
+ checkHighInput(input)
+ }
+ }
+
+ "Conditionally statements" should "create separate consequent and alternate scopes" in {
+ val input =
+ s"""|circuit scopes:
+ | module scopes:
+ | input i: UInt<1>
+ | output o: UInt<1>
+ | o <= i
+ | when i:
+ | node x = not(i)
+ | else:
+ | o <= and(x, i)
+ |""".stripMargin
+ assertThrows[CheckHighForm.UndeclaredReferenceException] {
+ checkHighInput(input)
+ }
+ }
}
object CheckSpec {
diff --git a/test/integration/RightShiftTester.fir b/test/integration/RightShiftTester.fir
index f15a1239..d85757b8 100644
--- a/test/integration/RightShiftTester.fir
+++ b/test/integration/RightShiftTester.fir
@@ -37,8 +37,8 @@ circuit RightShiftTester :
dut.clock <= clock
dut.reset <= reset
reg T_6 : UInt<2>, clock with : (reset => (reset, UInt<2>("h00")))
+ node T_8 = eq(T_6, UInt<2>("h03"))
when UInt<1>("h01") :
- node T_8 = eq(T_6, UInt<2>("h03"))
node T_10 = and(UInt<1>("h00"), T_8)
node T_13 = add(T_6, UInt<1>("h01"))
node T_14 = tail(T_13, 1)