Skip to content

Commit 4d37499

Browse files
author
Oron Port
committed
wip new syntax for FSM process
1 parent 5eab66a commit 4d37499

File tree

4 files changed

+120
-33
lines changed

4 files changed

+120
-33
lines changed

compiler/stages/src/test/scala/StagesSpec/PrintCodeStringSpec.scala

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -915,36 +915,36 @@ class PrintCodeStringSpec extends StageSpec:
915915
|end MatchWithParams""".stripMargin
916916
)
917917
}
918-
test("RTDesign process printing") {
919-
class Foo extends RTDesign:
920-
val cond = Bit <> IN
921-
val v = Bit <> VAR.REG init 0
922-
process:
923-
if (cond) x.goto
924-
else
925-
def z = step
926-
if (cond) z.goto else y.goto
927-
def x = step
928-
def y = step
929-
end Foo
930-
val top = (new Foo).getCodeString
931-
assertNoDiff(
932-
top,
933-
"""|class Foo extends RTDesign:
934-
| val cond = Bit <> IN
935-
| val v = Bit <> VAR.REG init 0
936-
| process:
937-
| if (cond) x.goto
938-
| else
939-
| def z = step
940-
| if (cond) z.goto
941-
| else y.goto
942-
| end if
943-
| def x = step
944-
| def y = step
945-
|end Foo""".stripMargin
946-
)
947-
}
918+
// test("RTDesign process printing") {
919+
// class Foo extends RTDesign:
920+
// val cond = Bit <> IN
921+
// val v = Bit <> VAR.REG init 0
922+
// process:
923+
// if (cond) x.goto
924+
// else
925+
// def z = step
926+
// if (cond) z.goto else y.goto
927+
// def x = step
928+
// def y = step
929+
// end Foo
930+
// val top = (new Foo).getCodeString
931+
// assertNoDiff(
932+
// top,
933+
// """|class Foo extends RTDesign:
934+
// | val cond = Bit <> IN
935+
// | val v = Bit <> VAR.REG init 0
936+
// | process:
937+
// | if (cond) x.goto
938+
// | else
939+
// | def z = step
940+
// | if (cond) z.goto
941+
// | else y.goto
942+
// | end if
943+
// | def x = step
944+
// | def y = step
945+
// |end Foo""".stripMargin
946+
// )
947+
// }
948948
test("wait statements") {
949949
class Foo extends EDDesign:
950950
val x = Bit <> OUT

plugin/src/main/scala-3.4-/plugin/Plugin.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ class Plugin extends StandardPlugin:
1111
PreTyperPhase(setting) ::
1212
TopAnnotPhase(setting) ::
1313
MetaContextPlacerPhase(setting) ::
14-
CustomControlPhase(setting) ::
1514
LoopFSMPhase(setting) ::
15+
CustomControlPhase(setting) ::
1616
DesignDefsPhase(setting) ::
1717
MetaContextDelegatePhase(setting) ::
1818
MetaContextGenPhase(setting) ::

plugin/src/main/scala-3.5+/plugin/Plugin.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ class Plugin extends StandardPlugin:
1212
PreTyperPhase(setting) ::
1313
TopAnnotPhase(setting) ::
1414
MetaContextPlacerPhase(setting) ::
15-
CustomControlPhase(setting) ::
1615
LoopFSMPhase(setting) ::
16+
CustomControlPhase(setting) ::
1717
DesignDefsPhase(setting) ::
1818
MetaContextDelegatePhase(setting) ::
1919
MetaContextGenPhase(setting) ::

plugin/src/main/scala/plugin/LoopFSMPhase.scala

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
3333
var fromBooleanSym: Symbol = uninitialized
3434
var customWhileSym: Symbol = uninitialized
3535
var dfcStack: List[Tree] = Nil
36+
val processDefs = mutable.Set.empty[Symbol]
3637

3738
override val runsAfter = Set(transform.Pickler.name)
38-
override val runsBefore = Set("MetaContextGen")
39+
override val runsBefore = Set("CustomControl")
3940

4041
override def prepareForDefDef(tree: DefDef)(using Context): Context =
4142
ContextArg.at(tree).foreach { t =>
@@ -61,6 +62,64 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
6162
}
6263
tree
6364

65+
def allDefsErrMsg(srcPos: util.SrcPos)(using Context): Unit =
66+
report.error("Process blocks must only declare `def`s or no `def`s at all.", srcPos)
67+
68+
def fsmStatCheck(tree: Tree, returnCheck: Boolean)(using Context): Unit =
69+
tree match
70+
case Block(stats, expr) =>
71+
fsmStatCheck(stats, tree.srcPos)
72+
expr match
73+
case Literal(Constant(_: Unit)) =>
74+
case _ =>
75+
stats.headOption match
76+
case Some(dd: DefDef) =>
77+
allDefsErrMsg(expr.srcPos)
78+
case _ =>
79+
fsmStatCheck(expr, returnCheck)
80+
case If(cond, thenp, elsep) =>
81+
fsmStatCheck(thenp, returnCheck)
82+
fsmStatCheck(elsep, returnCheck)
83+
case Match(scrut, cases) =>
84+
cases.foreach { case CaseDef(pat, guard, body) =>
85+
fsmStatCheck(body, returnCheck)
86+
}
87+
case _ if returnCheck =>
88+
tree match
89+
case x @ Ident(stepName) if processDefs.contains(x.symbol) =>
90+
case Apply(x @ Ident(stepName), _) if processDefs.contains(x.symbol) =>
91+
case _ =>
92+
report.error(
93+
"Process `def`s must end with a call to a process `def` (it could be the same `def`).",
94+
tree.srcPos
95+
)
96+
case Foreach(_, _, _, body, _) =>
97+
fsmStatCheck(body, returnCheck = false)
98+
case WhileDo(_, body) =>
99+
fsmStatCheck(body, returnCheck = false)
100+
case _ =>
101+
102+
def fsmStatCheck(trees: List[Tree], srcPos: util.SrcPos)(using Context): Unit =
103+
val (allDefs: List[DefDef] @unchecked, allSteps: List[Tree]) = (trees.partition {
104+
case _: DefDef => true
105+
case _ => false
106+
}): @unchecked
107+
if (allDefs.nonEmpty && allSteps.nonEmpty) allDefsErrMsg(srcPos)
108+
109+
var errFound = false
110+
// checking process defs syntax and caching the process def symbols
111+
allDefs.foreach {
112+
case dd @ DefDef(_, Nil, retTypeTree, _) if retTypeTree.tpe =:= defn.UnitType =>
113+
processDefs += dd.symbol
114+
case dd =>
115+
report.error("Unexpected process `def` syntax. Must be `def xyz: Unit = ...`", dd.srcPos)
116+
errFound = true
117+
}
118+
if (!errFound)
119+
allDefs.foreach { dd => fsmStatCheck(dd.rhs, returnCheck = true) }
120+
allSteps.foreach { step => fsmStatCheck(step, returnCheck = false) }
121+
end fsmStatCheck
122+
64123
object Step:
65124
def unapply(tree: Tree)(using Context): Option[Tree] =
66125
if (tree.tpe <:< stepRef && !(tree.tpe =:= defn.NothingType))
@@ -144,6 +203,29 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
144203
ref(customWhileSym).appliedTo(guard).appliedTo(tree.body).appliedTo(dfc)
145204
}.getOrElse(tree)
146205

206+
case class ProcessForever(scopeCtx: ValDef, block: Tree)
207+
object ProcessForever:
208+
def unapply(tree: Tree)(using Context): Option[ProcessForever] =
209+
tree match
210+
case Apply(
211+
Apply(
212+
Select(Ident(process), forever),
213+
List(
214+
Block(
215+
List(dd @ DefDef(anonfun, List(List(scopeCtx: ValDef)), _, _)),
216+
_: Closure
217+
)
218+
)
219+
),
220+
_
221+
)
222+
if anonfun.toString.startsWith("$anonfun") && process.toString == "process" && forever
223+
.toString == "forever" =>
224+
Some(ProcessForever(scopeCtx, dd.rhs))
225+
case _ =>
226+
None
227+
end ProcessForever
228+
147229
override def transformApply(tree: Apply)(using Context): Tree =
148230
tree match
149231
case fe @ Foreach(iter, range, filters, body, dfc) =>
@@ -163,6 +245,10 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
163245
.appliedTo(iter.genMeta, range, ifGuards)
164246
.appliedTo(updatedBody)
165247
.appliedTo(dfc)
248+
case ProcessForever(scopeCtx, block) =>
249+
fsmStatCheck(block, returnCheck = false)
250+
processDefs.clear()
251+
tree
166252
case _ =>
167253
tree
168254

@@ -201,6 +287,7 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
201287
toFunc1Sym = requiredMethod("dfhdl.core.r__For_Plugin.toFunc1")
202288
fromBooleanSym = requiredMethod("dfhdl.core.r__For_Plugin.fromBoolean")
203289
customWhileSym = requiredMethod("dfhdl.core.DFWhile.plugin")
290+
processDefs.clear()
204291
ctx
205292
end prepareForUnit
206293
end LoopFSMPhase

0 commit comments

Comments
 (0)